A. Deletions of Two Adjacent Letters

Code

void solve()
{
    string s;	char c;
    cin >> s >> c;
   
   	bool flag = false;
   	for (int i = 0; i < s.length(); i++)
   	    if (s[i] == c && i % 2 == 0)
   	    {
   	        flag = true;
   	        break;
   	    }	
    	
    if (flag)	puts("YES");
    else puts("NO");
}

B. DIV + MOD

Code

void solve()
{
    int l, r, a;
    cin >> l >> r >> a;

    int res = r / a + r % a;
    int m = r / a * a - 1;

    if (m >= l) res = max(res, m / a + m % a);
    cout << res << endl;
}

C. Weight of the System of Nested Segments (排序)

解题思路

输出的最小权值其实就是m - 2 * n 个 权值最小的点的和
OS: 很简单的一道题,但是一开始一直以为输出的是端点坐标,结果竟然是“输入编号”

Code

struct point
{
    int id, x, w;
};

bool cmpw(point a, point b) {return a.w < b.w;}
bool cmpx(point a, point b) {return a.x < b.x;}

void solve()
{
    int n, m, sum = 0;   cin >> n >> m;
    vector<point> points(m);

    for (int i = 0; i < m; i++)    cin >> points[i].x >> points[i].w, points[i].id = i + 1;  // 输入的同时要存入"输入编号(id)"

    sort(points.begin(), points.end(), cmpw);  // 按权值从小到大排序

    for (int i = 0; i < m; i++)
        if (i < 2 * n) sum += points[i].w;  // 前2 * n个小的权值相加
        else points.pop_back();  // 后面的全部删掉,这样后面排序就只剩用到的点了

    sort(points.begin(), points.end(), cmpx);  // 按坐标从小到大排序
	
    cout << sum << endl;
	// 一首一末输出“输入编号”
    for (int i = 0; i < n; i++)    cout << points[i].id << ' ' << points[2 * n - i - 1].id << endl;  
    cout << endl;
}

D. Twist the Permutation(数学/逆向思维)

解题思路

TIP1:答案总是存在的
TIP2:通过进行反向操作来还原

Code

void solve()
{
    int n, x, pos[N],res[N];  cin >> n;
    for (int i = 1; i <= n; i++)    cin >> x, pos[x] = i;  // 记录每个数的最后位置

    for (int i = n; i > 0; i--)
    {
        /*
            计算出从原来的位置循环了几次,如i = 6, 假设pos[i] = 4,
            则pos[i] % i = 4 % 6 = 4 次
        */
        res[i] = pos[i] % i;    
        for (int j = 1; j < i; j++)
            pos[j] = (pos[j] + i - res[i]) % i;  // 这里是还原操作
            /* 
                (i - res[i]) 实则是还原位置的次数,如i = 6, pos[i] = 4, 那么需要6 - 4 = 2次
                即pos = pos + 2 = 4 + 2 = 6, 完成还原
            */
    }

    for (int i = 1; i <= n; i++)    cout << res[i] << ' ';
    cout << '\n';
}

E. Rescheduling the Exam(贪心)

Code

int n, d;
int work(vector<int> &b)  // 用来找到最佳方案
{
	int minn = 0x3f3f3f3f, maxn = -1;
	for (int i = 1; i < n; i++)
	{
		minn = min(minn, b[i] - b[i - 1] - 1);
		maxn = max(maxn, b[i] - b[i - 1] - 1);
	}
	/*两种方案:1.放在最后一天, 2. 放在最大区间的中间
		因为题目要求结果尽可能大,所以这两种方案取较大值;
		然后再跟遍历过程中找到的最小区间取较小值
	*/
	return min(minn, max(d - b.back() - 1, (maxn - 1) / 2));
}

void solve()
{
    cin >> n >> d;
    vector<int> a(n + 1);
	
    int min_val = d, min_pos = 0; 
    for (int i = 1; i <= n; i++)
    {
    	cin >> a[i];
        if (a[i] - a[i - 1] - 1 < min_val)  // 找到最短休息时间的位置和值
        {
            min_val = a[i] - a[i - 1] - 1;
            min_pos = i;
        }
    }	
        
    vector<int> b;
    for (int i = 0; i <= n; i++)  // 因为要计算第一门考试之前的休息时间,所以要加入0
        if (i != min_pos)	b.push_back(a[i]);

    int res = work(b);
    if (min_pos > 1)	b[min_pos - 1] = a[min_pos];
    /* 这里这么做是因为一开始找到的[min_pos - 1, min_pos]这个区间由两个端点构成,
        第一次work计算了a[min_pos - 1]这个点得出的最佳方案,
        那么第二次就用a[min_pos]替换a[min_pos - 1],计算它得出的最佳方案
    */  
    cout << max(res, work(b)) << endl;  // 对两种端点得出的最佳方案取较大值
}

上一篇 下一篇