codeforces round 799

传送门

799

A

计算 \(b, c, d\) 中有几个数比 \(a\) 大就好

B

题意

一次只能删任意两个数,最后只能留下不同的数,想要留下的数最多

思路

  • 最好的情况,最后留下的个数为 \(cnt\) (种类数)
  • 计算 \(n - cnt\) 。偶数则可以全部删除,奇数就要从 \(cnt\) 中删一个来配对

C

求对角线交点的坐标

误区 : 并不是一行或一列只有一个 # 的就是交点 (除掉边界之后)

以行为例,只有 上一行和下一行都有两个 #这一行有一个的才是

D

傻傻地不断判断是否为回文,直到和初状态重合

bool check (int x, int y) {
    string s1, s2;
    if (x < 10) s1 = '0' + to_string (x);
    else s1 = to_string (x);
    if (y < 10) s2 = '0' + to_string (y);
    else s2 = to_string (y);
    reverse (s2.begin (), s2.end());
    if (s1 == s2) return true;
    return false;
}

void solve () {
    string s; int x;
    cin >> s >> x;
    int dh = x / 60, dm = x % 60;
    int sh = (s[0] - '0') * 10 + (s[1] - '0');
    int sm = (s[3] - '0') * 10 + (s[4] - '0');
    int cnt = check (sh, sm) ? 1 : 0;
    if (x == 1440) {
        cout << cnt << '\n';
        return;
    }
    int hh = sh, mm = sm;
    while(1) {
        hh = hh + dh, mm = dm + mm;
        if (mm >= 60)   hh += (mm / 60), mm %= 60;
        hh %= 24;
        if (hh == sh && mm == sm) break;
        if (check (hh, mm)) cnt ++;      
    }
    cout << cnt << '\n';
}

E

题意

一次只能删 第一个 最后一个数,希望用最少的步骤使最后为指定和

思考

❓无法判断是删第一个数好,还是最后一个数好

转换思路

  • 想要用最少步骤 --> 删去的数最少

  • 只能删两边 --> 最后的序列连续,要么在中间,要么在两边

那么,要求的就是 满足指定和这个条件的,最长连续子序列

❓如何求最长连续子序列 且 满足条件

前缀和二分

以一个点为起始点,利用二分找到满足条件的后面的点,如果最大的那个都不满足,就可以结束了

void solve()
{
    int n, s, ma = 0; cin >> n >> s;
    vector<int> a(n + 1), ss(n + 1);
    for(int i = 1; i <= n; i++) {
    	cin >> a[i];
    	ss[i] = ss[i - 1] + a[i];
    }
    if(ss[n] == s) {cout << 0 << '\n'; return;}
    if(ss[n] < s) {cout << -1 << '\n'; return;}
    for(int i = 1; i <= n; i++) {
    	int u = s + ss[i - 1], y;
    	auto q = upper_bound(ss.begin(), ss.end(), u);
    	if(q == ss.end()) {
    		if(ss[n] == u) y = n;
    		else break;
    	}
    	y = q - ss.begin() - 1;
    	ma = max(ma, y - i + 1);
    }
    cout << n - ma << '\n';
}

F

找到三个数相加所得数的个位数是3

傻方法 --- 手动枚举

最大的情况 \(9 + 9 + 9\)\(27\),只有三种情况 : \(3, 13, 23\)

稍微省力一点的方法 --- 自动枚举

将所有个位数 出现次数小于等于 \(3\) 的数都放进容器,然后一个个匹配,看是否满足

附上手动枚举的代码

void solve()
{
    int n; cin >> n;
    map<int, int> mp;
    for(int i = 0; i < n; i++) {
    	string s;
    	int w; cin >> w;
    	s = to_string(w);
    	int u = s.size();
    	int q = s[u - 1] - '0';
    	mp[q]++;
    }
    if(mp[0]) {
    	if(mp[0] >= 2 && mp[3] >= 1) {cout << "YES\n"; return;}
    	if(mp[0] >= 1) {
    		if((mp[1] >= 1 && mp[2] >= 1) || (mp[4] >= 1 && mp[9] >= 1) || (mp[5] >= 1 && mp[8] >= 1) || (mp[6] >= 1 && mp[7] >= 1)) {cout << "YES\n"; return;}
    	} 
    }
    if(mp[1] >= 1) {
    	if((mp[1] >= 3) || (mp[3] >= 1 && mp[9] >= 1) || (mp[4] >= 1 && mp[8] >= 1) || (mp[5] >= 1 && mp[7] >= 1) || (mp[6] >= 2)) {cout << "YES\n"; return;}
    }
    if(mp[2] >= 1) {
    	if((mp[2] >= 2 && mp[9] >= 1) || (mp[3] >= 1 && mp[8] >= 1) || (mp[4] >= 1 && mp[7] >= 1) || (mp[5] >= 1 && mp[6] >= 1)) {cout << "YES\n"; return;}
    }
    if(mp[3] >= 1) {
    	if((mp[3] >= 2 && mp[7] >= 1) || (mp[4] >= 1 && mp[6] >= 1) || mp[5] >= 2) {cout << "YES\n"; return;}
    }
    if((mp[4] >= 2 && mp[5] >= 1) || (mp[5] >= 1 && mp[9] >= 2) || (mp[6] >= 1 && mp[8] >= 1 && mp[9] >= 1) || (mp[7] >= 2 && mp[9] >= 1) || (mp[7] >= 1 && mp[8] >= 2)) {cout << "YES\n"; return;}
    cout << "NO\n";
}

G

将题目所给公式化简 -- 每两个连续的数之间,后面都是前面的两倍以上

不用担心不相连的数不满足这种关系,2是1的两倍以上,3是2的两倍以上,那么3肯定是1的四倍以上,直接写就好

void solve()
{
    int n, k; cin >> n >> k;
    int cnt = 0, l = 0, r = 0;
    vector<ll> a(n);
    for(int i = 0; i < n; i++) cin >> a[i];
    for(int i = 1; i < n; i++) {
    	if(a[i - 1] < a[i] * 2) r++;
    	else cnt += max(0, r - l + 1 - k), l = i, r = l;
    }
    cnt += max(0, r - l + 1 - k);
    cout << cnt << '\n';
}

H

此题本人看了题解才明白,很妙了

很详细的题解

记录每一个数出现的下标,循环遍历每一个数去作为x

使用前缀和计算最大收益,x记为1,非x记为-1

计算前缀和时,当前位置的收益为 上一个x的位置的收益 - 上一个x到此处的距离(这中间都是非x,都是-1)再加上1(自身是个x)

计算完之后寻找一个区间使得和最大,如果s[l] > s[r] ,就说明要变更区间了,l = r

void solve()
{
    int n; cin >> n;
    vector<int> a(n + 1);
    map<int, vector<int>> v;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        v[a[i]].push_back(i);
    }
    int l = 1, r = 1, res = a[1], cnt = 1;
    for (auto& [q, w] : v) {
        int u = w.size();
        vector<int> s(u + 1);
        for (int i = 1; i < u; i++) {
            s[i] = s[i - 1] - (w[i] - w[i - 1] - 1) + 1;
        }
        int i = 0;
        for (int j = 1; j < u; j++) {
            int z = s[j] - s[i] + 1;
            if (z > cnt) {
                cnt = z, res = q, l = w[i], r = w[j];
            }
            if (s[i] > s[j]) i = j;
        }
    }
    cout << res << ' ' << l << ' ' << r << '\n';
}
``
posted @ 2025-07-07 19:33  PeachyGalaxy  阅读(278)  评论(0)    收藏  举报