Codeforces Round 966 (Div. 3) ABCDEF

A题:Primary Task

题意

Dmitry写了t个整数,但是在写幂的时候写错了,将^符号给省略掉了。问哪几个是写幂时写错的

思路

写错的数符合10X,其中X(X>=2)是不含前导零的正整数,我们依此进行判断即可。

代码

inline void solve() {
     string s; cin >> s;
     int n = s.size();
     if (n < 2) return cout << "NO" << endl, void();
     if (s[0] == '1' && s[1] == '0') {
        if (n == 3 && s[2] >= '2' || n > 3 && s[2] != '0') cout << "YES" << endl; 
        else cout << "NO" << endl;
     }else cout << "NO" << endl;
	 return;
}

B题: Seating in a Bus

题意

汽车上坐位置,除了第一个人,其他人坐位置的时候两旁一定要有一个人,问题目给的坐位置顺序是否满足题意

思路

模拟

代码

inline void solve() {
     int n; cin >> n;
     vector vis(n + 2);
     bool flag = true;
     for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        vis[x] = 1;
        if (i == 1) continue;
        if (!(vis[x + 1] || vis[x - 1])) flag = false;
     }
     cout << (flag ? "YES" : "NO") << endl;
	 return;
}

C题:Numeric String Template

题意

给定一个数组a,再给若干个字符串,要求a数组中值相等元素的位置和字符串匹配,即若ai = aj,si = sj

思路

模拟

我们用O(n)扫,就记录每个位置上与哪个位置上的元素相等,然后输入字符串后进行相同的判断即可。但是要注意样例一,我们还需判断使用到的不同种类的字符数量是否与数组中不同值的数量相同。

代码

inline void solve() {
     int n; cin >> n;
     vector pos(n + 1);
     map vis;
     for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        if (!vis[x]) pos[i] = i, vis[x] = i;
        else pos[i] = vis[x];
     }
     int q; cin >> q;
     while (q -- ) {
        string s; cin >> s;
        int c = vis.size(), m = s.size();
        s = ' ' + s;
        bool flag = (m == n);
        if (!flag) {
            cout << "NO" << endl;
            continue;
        }
        vector t(26);
        for (int i = 1; i <= m; i ++ ) {
            if (!t[s[i] - 'a']) c -= 1;
            t[s[i] - 'a'] += 1;
            if (s[i] != s[pos[i]]) flag = false;
        }
        cout << ((flag && !c) ? "YES" : "NO") << endl;
     }
	 return;
}

D题:Right Left Wrong

题意

给定一个数组和字符串,每次可以选择i和j,要求i和j对应的字符分别为L和R,这样可以获得i和j包括在内的区间上数组的值,问最大分数是多少? 

思路

贪心+双指针

首先肯定是范围越大越好,那么我们从左往右找第一个L,从右往左找第一个R,这样是不是获得的就最多呢?

最后一个样例是22,答案与上述思路不符

我们仔细观察题目,虽然选过区间i,j后,区间内的元素不能再选,但是我们可以先选区间里面的,再选i和j,这样不就更大了吗?

先取区间里面的,再取区间跟先取区间再取里面的没有任何区别

代码

inline void solve() {
     int n; cin >> n;
     vector a(n + 1);
     for (int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        a[i] += a[i - 1];
     }
     string s; cin >> s;
     s = ' ' + s;
     int j = n;
     while (j >= 1 && s[j] != 'R') j -= 1;
     ll ans = 0;
     for (int i = 1; i < j; i ++ ) {
        if (s[i] == 'R') continue;
        ans += a[j] - a[i - 1];
        j -= 1;
        while (j > i && s[j] != 'R') j -= 1;
     }
     cout << ans << endl;
	 return;
}

E题:Photoshoot for Gorillas

题意

给定一个NxM的矩形,然后w个身高为ai的大猩猩,每次取边长为k的正方形区间,然后对答案的贡献为此区间的大猩猩身高总和,问合理安排猩猩分布后,所有区间总和最大是多少

思路

贪心

我们只需找到出现最多的位置和身高最大的猩猩,然后放到该位置上就行了

然后对于次大的也是如此

然后题目就变成了一个格子能够被一个边长为k的正方形覆盖多少次

简单地,我们只需找到上下左右四个边界即可,这样就能找出覆盖次数了

代码

inline void solve() {
     int n, m, k; cin >> n >> m >> k;
     int w; cin >> w;
     vector a(w + 1);
     for (int i = 1; i <= w; i ++ ) cin >> a[i];
     vector p;
     for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            int u = max(i - k + 1, 1), d = min(n, i + k - 1);
            int l = max(j - k + 1, 1), r = min(m, j + k - 1);
            ll now = 1ll * (d - u + 1 - k + 1) * (r - l + 1 - k + 1);
            p.push_back(now);
        }
     }
     sort(p.begin(), p.end(), greater<>());
     sort(a.begin() + 1, a.end(), greater<>());
     ll ans = 0;
     for (int i = 1; i <= w; i ++ ) {
        ans += 1ll * a[i] * p[i - 1];
     }
     cout << ans << endl;
	 return;
}

F题:Color Rows and Columns

题意

见题目

思路

贪心+dp

我们首先可以试试定义一维dp[i]为得到i分的最少操作次数

然后我们考虑转移

我们先考虑单个矩形

如果长度为a和b(a

我们肯定是先放长度小的一边,这样可以得到1分

现在矩形就变成了a和b-1了(因为放了a个,b列会少一列)

我们还是放a和b-1中较小的一个可以得到1分,所以这就是最优的放法,每次放边长较小的那一个

当a一直小于b的时候,我们一直放a

当出现相等情况的时候 

a        a

a-1        a

a-1        a-1

a-2        a-1

a-2        a-2 

 我们会按上述方法贪心放,每次的花费为

a        a-1        a-1        a-2        a-2        a-3        a-3

后面是一个等差数列

转移的话以实现l分来转移,更新dp[j+l]的值即可

代码

inline void solve() {
     int n, k; cin >> n >> k;
     vector dp(k + 1, (int)MOD);
     dp[0] = 0;
     for (int i = 1; i <= n; i ++ ) {
        int a, b; cin >> a >> b;
        if (a > b) swap(a, b);
        for (int j = k; j >= 0; j -- ) {
            for (int l = 1; l <= a + b && j + l <= k; l ++ ) {
                if (l <= b - a) {
                    dp[j + l] = min(dp[j + l], dp[j] + a * l);
                }else {
                    int temp = l - b + a;
                    int cost = (b - a) * a, num = (temp - 1) / 2;
                    cost += a * temp - (1 + num) * num / 2 * 2;
                    if (temp % 2 == 0) cost -= num + 1;
                    dp[j + l] = min(dp[j + l], dp[j] + cost);
                }
            }
        }
     }
     ll ans = (dp[k] == MOD ? -1 : dp[k]);
     cout << ans << endl;
	 return;
}

 

你可能感兴趣的:(Codeforces,算法,c++,数据结构)