Codeforces Round #664 (Div. 2) A-D --白话题解

A:

4种颜色的球,红绿蓝白各r,g,b,w个,可以进行若干次操作,每次将一个r、g、b同时转化为白色
即r–,g–,b–,w+=3
问能否使得最后的四种颜色能排列成回文串

能构成回文的情况是四种不同字母中,至多只有一种字母数量为奇数
而每一次操作同时改变四种颜色的奇偶性,所有只要判断能否用少于一次操作使之至多只有一种字母数量为奇数

int main()
{   
    int T;
    cin >> T;
    while (T--) {
        ll r, g, b, w;
        cin >> r >> g >> b >> w;
        int numofji = 0;
        if (r % 2 == 1) numofji++;
        if (g % 2 == 1) numofji++;
        if (b % 2 == 1) numofji++;
        if (w % 2 == 1) numofji++;
        if (numofji <= 1) cout << "Yes" << endl;
        else {
            if (r > 0 && g > 0 && b > 0) {
                r--, g--, b--;
                w += 3;
                numofji = 0;
                if (r % 2 == 1) numofji++;
                if (g % 2 == 1) numofji++;
                if (b % 2 == 1) numofji++;
                if (w % 2 == 1) numofji++;
                if (numofji <= 1) cout << "Yes" << endl;
                else cout << "No" << endl;
            }
            else cout << "No" << endl;
        }
    }
 return 0;
}

B:

给n*m的矩阵,给一个起点(起点不在边界上),每次能跳到同一行或同一列的任意位置
找出一种方案使得恰好跳到每个位置1次

构造方法蛮多的,我是先跳到第一列,然后不断往上跳一格,从第一行往上跳就是到最后一行
然后跳n-1次后(跳满一列)往右跳一格。
特判一下起点位置所在的那一列即可

int v[1000][1000] = {};
int main()
{   
    int n, m, sx, sy;
    cin >> n >> m >> sx >> sy;
    v[sx][sy] = 1;
    cout << sx << ' ' << sy << endl;
    v[sx][1] = 1;
    cout << sx << ' ' << 1 << endl;
    int tx=sx,ty=1;
    F(j, 1, m) {
        F(i, 1, n-1) {
            if (tx == 1) tx = n; else tx--;
            if (tx == sx && ty == sy)continue;
            cout << tx << ' ' << ty << endl;
        }
        ty++;
        if (ty <= m) {
            cout << tx << ' ' << ty << endl;
        }
    }
    return 0;
}

C:

给两列数字n个ai,m个bi,要求对每一个ai选择一个bi,做 按位和 运算
得到n个ci 对这个n个ci求连续的 按位或 运算,要求最后的答案最小值

n、m都小于200,ai、bi都小于2^9(小于512)
所以可以朝暴力去想解法。
我是首先把每一个ai对应的所有ci都算出来(最多200*200个)
然后用 x 枚举0~511,判断对每一个ai能不能找到对应的ci使得 ci | x = x ( x 的二进制的1包含了 ci 的二进制的1)

int a[1000], b[1000];
int c[1000][1000];
int main()
{   
    int n, m;
    cin >> n >> m;
    F(i, 1, n) {
        scanf("%d", a + i);
    }
    F(i, 1, m) {
        scanf("%d", b + i);
    }
    F(i, 1, n) {
        F(j, 1, m) {
            c[i][j] = a[i] & b[j];
        }
    }
    F(tar, 0, 511) {
        int f1 = 0;
        F(i, 1, n) {
            int f2 = 0;
            F(j, 1, m) {
                if ((c[i][j] | tar) == tar) {
                    break;
                }
                if (j == m) f2 = 1;//对于这个a 无法找到它形成的c使得二进制被包含在tar中
            }
            if (f2) {
                f1 = 1; break;
            }
        }
        if (!f1) {
            cout << tar << endl;
            break;
        }
    }
    return 0;
}

D:

n天要说n句话,每句话有个权重ai,每次说出了权重超过m的话,就得有d天不能说话(不包含说出这句话的这一天),求一种说话的顺序使得总权重和最大

(一直更着题目作者的背景在死命想模拟,其实抽象成上面的题目多么简单!!)
首先从大到小排序,然后枚举说多少句大话(权重超过m的话),更具这个值贪心地求出当前的最大权重,然后更新。(这一步在预处理前缀和后可以O(1)完成)

int a[100010];
ll sum[100010] = {};
int n, d, m;
void qs(int L, int R);//从大到小快排
ll calc(int L, int len) {
    if (len + L - 1 > n) {
        return sum[n] - sum[L - 1];
    }else
    return sum[len + L - 1] - sum[L - 1];
}
int main()
{   
    cin >> n >> d >> m;
    F(i, 1, n) {
        scanf("%d", a + i);
    }
    qs(1, n);
    int numofBig = 0;
    F(i, 1, n) {
        if (a[i] > m) numofBig++;
        sum[i] += sum[i - 1] + a[i];
    }
    ll maxans = 0;
    ll tmpans = 0;
    F(i, 0, numofBig) {
        int needForBig;
        if (i == 0) needForBig = 0; else needForBig = (i - 1) * (d + 1) + 1;
        if (n - needForBig < 0) break;
        tmpans = calc(1, i) + calc(numofBig + 1,n - needForBig);

        if (tmpans > maxans)maxans = tmpans;
    }
    cout << maxans << endl;
    return 0;
}

E题 图论,好好研究看看能不能看懂呜呜呜

你可能感兴趣的:(ACMP,算法,数据结构,字符串)