Educational Codeforces Round 176 (Rated for Div. 2) (A~D)

前言

D题场上爆写十二发,刚结束就找到问题一发通过...

A. To Zero (签到)

判断一下奇偶,向上取整。

    void solve(){
    cin >> n >> k;
    int res = 0;
    if(n % 2 == 1 && k % 2 == 1) {
        n -= k;
        res++;
    }
    else if(n % 2 == 1 && k % 2 == 0) {
        n -= (k - 1);
        res++;
    } 
    if(n <= 0)  {
        cout << 1 << endl;;
        return ;
    }
    if(k % 2 == 1) k--;
    cout << res + (n + k - 1) / k << endl;;
}

B. Array Recoloring (贪心)

题意粘大锅,场上又是看公共,又是看榜,吓得没敢写先去写C了。
题意是先将任意k个元素标记,然后每次可以将一个标记向相邻元素延伸,问最后一个被标记的元素和一开始被标记的元素的和最大值。
如果k==1,那么只能选择数组中一个元素,再在数组两侧选其一。
否则,一定可以以一种方式取出前k+1个大的元素。

    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    if(k > 1) {
        sort(a + 1, a + n + 1, greater<int>());
        int res = 0;
        for(int i = 1; i <= k + 1; i++) {
            res += a[i];
        }
        cout << res << endl;
    }
    else {
        int res = 0;
        for(int i = 2; i <= n; i++) {
            res = max(res, a[1] + a[i]);
        }
        for(int i = 1; i < n; i++) {
            res = max(res, a[n] + a[i]);
        }
        cout << res << endl;
    }

C. Two Colors (贪心)

在m个颜色中选两个涂满栅栏,要求相同颜色连续,且颜色数量有限制。问方案数。
如果确定一种颜色以及要涂多少格,那么另外一种颜色只要满足数量大于等于剩下格子,就可以成功涂满。
因此可以枚举左侧的颜色涂i格,查找有多少个颜色大于等于i,再查找多少个颜色大于等于n-i,然后相乘。
注意一下去重即可。

cin >> n >> m;
    vector<int> v;
    for(int i = 1; i <= m; i++) {
        cin >> a[i];
        v.push_back(a[i]);
    }
    sort(v.begin(), v.end());
    int ans = 0;
    if(n % 2 == 1) {
        for(int i = 1; i <= n / 2; i++) {
            int x = lower_bound(v.begin(), v.end(), i) - v.begin();
            int y = lower_bound(v.begin(), v.end(), n - i) - v.begin();
            x = m - x;
            y = m - y;
            //cerr << x << " " << y << endl;
            ans += (x - 1) * y;
        }
        ans *= 2;
    }else {
        for(int i = 1; i < n / 2; i++) {
            int x = lower_bound(v.begin(), v.end(), i) - v.begin();
            int y = lower_bound(v.begin(), v.end(), n - i) - v.begin();
            x = m - x;
            y = m - y;
            ans += (x - 1) * y;
        }
        ans *= 2;
        int x = lower_bound(v.begin(), v.end(), n / 2) - v.begin();
        int y = lower_bound(v.begin(), v.end(), n / 2) - v.begin();
        x = m - x;
        y = m - y;
        ans += (x - 1) * y;
    }
    cout << ans << endl;
}

D. Palindrome Shuffle (深搜)

保证二进制下两个数分别右移 \(l\),\(r\),使得结果相等。
实际上就是如何用 \(1\)~\(62\) 之间的数填满 \(l\)\(r\) 最优。每个数只能用一次。
写了一个莫名其妙的贪心果不其然挂了。然后想到整数拆分,一个数只能用一次可以保证复杂度。
定义 \(f[i][j][p]\) 表示 \(l\) 还差 \(i\) 位没填,\(r\) 还差 \(j\) 位,目前最大可以使用 \(p\)
注意\(vis\)记忆化

注意有特判 \(2,3\), \((2,2)\)是无法拆分的

可能还有其他特判,我这里采取直接先算出ans的最大值。

#include<bits/stdc++.h>
using namespace std;
#define SHOJIG ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n' 
#define x1 xxxx
#define y1 yyyy
#define int long long
#define lowbit(x) (x & (-x))
typedef long long ll;
const int N = 1e3 + 9, inf = (1ll << 60);
int n, m, k;
int a[N];
int b[N];
int vis[100][100][100];
int f[100][100][100];
int c[100][100]; 
int p1, p2;
int same(int i, int j) {   //判断分别右移i,j之后是否相等
    if(p1 - i != p2 - j) return 0;
    for(int x = 0; x + i <= p1; x++) {
        if(a[x + i] != b[x + j]) return 0;
    }
    return 1;
}
void dfs(int l, int r, int p) {
    if(l == 0 && r == 0) {  // 初始化写搜索里面了
        f[l][r][p] = 0;
        return;
    }
    if(vis[l][r][p] == 1) return;
    for(int i = 1; i <= p; i++) {
        if(l >= i) {
            dfs(l - i, r, i - 1);
            if(f[l - i][r][i - 1] != -1) {
                if(f[l][r][p] == -1) f[l][r][p] = f[l - i][r][i - 1] + (1ll << i);
                else f[l][r][p] = min(f[l][r][p], f[l - i][r][i - 1] + (1ll << i));
            }
        }
        if(r >= i) {
            dfs(l, r - i, i - 1);
            if(f[l][r - i][i - 1] != -1) {
                if(f[l][r][p] == -1) f[l][r][p] = f[l][r - i][i - 1] + (1ll << i);
                else f[l][r][p] = min(f[l][r][p], f[l][r - i][i - 1] + (1ll << i));
            }
        }
    }
    vis[l][r][p] = 1;
}
void solve(){
    for(int i = 0; i <= 80; i++) {
        a[i] = b[i] = 0;
    }
    cin >> n >> m;
    if(n == m) {
        cout << 0 << endl;
        return ;
    }
    p1 = 0; // 二进制化,保留了最高位的0,方便比较使用
    while(n) {
        a[p1++] = n % 2;
        n /= 2;
    }
    p2 = 0;
    while(m) {
        b[p2++] = m % 2;
        m /= 2;
    }
    int ans = inf;
    ans = (1ll << p1 ) + (1ll << p2 + 1); // 处理特判
    for(int i = 0; i <= p1; i++) {
        for(int j = 0; j <= p2; j++) {
            if(same(i, j)) {
                if(c[i][j] != inf)
                    ans = min(ans, c[i][j]);
            }
        }
    }
    cout << ans << endl;
}
signed main(void){
    SHOJIG 
    int _ = 1;
    cin >> _;
    for(int i = 0; i < 63; i++) {
        for(int j = 0; j < 63; j++) {
            for(int p = 0; p < 63; p++) {
                f[i][j][p] = -1;
            }
        }
    }
    for(int i = 0; i < 63; i++) {
        for(int j = 0; j < 63; j++) {
            for(int p = 0; p < 63; p++) {
                dfs(i, j, p);
            }
        }
    }
    for(int i = 0; i < 63; i++) { // 计算最后 i,j 的答案
        for(int j = 0; j < 63; j++) {
            c[i][j] = inf;
            for(int p = 0; p < 63; p++) {
                if(f[i][j][p] != -1)
                    c[i][j] = min(c[i][j], f[i][j][p]);
            }
        }
    }
    for(int i = 1;i <= _; i++) solve();
}
posted @ 2025-03-18 01:43  SHOJIG  阅读(175)  评论(0)    收藏  举报