cf掉分日记-Educational Codeforces Round 123 (Rated for Div. 2) A - D

A - Doors and Keys

题目大意:

给三个钥匙用三个小写字母 r, g, b 表示,再给出三扇门 R, G, B ,问你顺序走过去,是否能开每一扇门。即所有字母都满足小写的在大写前面即可。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
int a[N];
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        string s; cin >> s;
        int r, g, b, R, G, B;
        for (int i = 0; i < 6 ; i ++){
            if (s[i] == 'r') r = i;
            else if (s[i] == 'R') R = i;
            else if (s[i] == 'g') g = i;
            else if (s[i] == 'G') G = i;
            else if (s[i] == 'b') b = i;
            else B = i;
        }        
        if (r < R && g < G && b < B){
            cout << "YES" << endl;
        }
        else cout << "NO" << endl;
    }
    return 0;
}

B - Anti-Fibonacci Permutation

题目大意:

输入 n,输出 满足 \(a[i - 1] + a[i - 2] != a[i]\) (3 <= i <= n),的 n 个长度为 n 的排列。

分析:

一开始急于求成了,直接暴力next_permutation() , 然后 暴力check t了。后来想想大概是个构造吧, 从最简单的开始想,逆序肯定是满足题意的, 如 5 4 3 2 1,然后发现交换其中相邻的两项依旧是满足的。swap 出了 n - 1 种,加上初始的一种刚好 n 种,然后没细想就上了,可能有更优的构造吧。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
int a[N];
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n; cin >> n;
        for (int i = 1 ; i <= n ; i ++) a[i] = n + 1 - i;

        for (int i = 1 ; i <= n ; i ++){
            cout << a[i] << ' ';
        }
        cout << endl;
        for (int i = 1 ; i < n ; i ++){
            swap (a[i], a[i + 1]);
            for (int j = 1 ; j <= n ; j ++){
                cout << a[j] << ' ';
            }
            cout << endl;
            swap (a[i], a[i + 1]);
        }
    }
    return 0;
}

C - Increase Subarray Sums

题目大意:

如题名,最大连续子串和。经典问题了,本题的变式是,可以做 k 次操作,每次操作可以选择任意个位置加上 x,令 f(k) 等于k次操作最大连续子串和的可能最大值。求 \(f(0)\)\(f(n)\)

分析:

赛中一开始走了很多弯路,一开始以为这是一个递推的过程,显然 \(f(1)\) 是可以 由 \(f(0)\) 直接推出来,但是 \(f(n)\) 选择加上x的点可能和 \(f(n - 1)\) 完全不一样的

10 3

-100 -100 1 1 1 -100 0 1 1 0

在上面这个样例中, \(f(3)\) 是选择 [1, 1, 1] 这一段加上3 ,结果为 12, 但是 \(f(4)\) 是选择 [0, 1, 1, 0] 一段,结果是 14。由此可以看出,选法并不能递推。这是我思考过程中的一个误区。

从上面跳出来之后,我很快就发现了正解。给一个区间的所有数加上某个值,使得这个区间变成最大的区间,那这个区间在同长度的区间中本身就是最大的了。于是用 \(n^2\) 的时间枚举区间,找到某一长度区间的最大值,记作 dp[i],表示长度为 i 的区间的最大值。那么对于 k 次操作,我们就可以更新 dp数组,使其中的数字加上 \(min (i, k) * x\) ,然后取更新后的数组的最大值就是答案。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e5+7;
const double eps=1e-6;
const int mod=1e9+7;
int a[N], q[N], dp[N], dp2[N];
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n, x; cin >> n >> x;
        for (int i = 1 ; i <= n ; i ++){
            cin >> a[i];
            q[i] = q[i - 1] + a[i]; 
            dp[i] = -1e9;
        }
        for (int i = 1 ; i <= n ; i ++){
            for (int j = 1 ; j + i - 1 <= n ; j ++){
                int l = j, r = i + j - 1;
                dp[i] = max(q[r] - q[l - 1], dp[i]);
            }
        }
        for (int k = 0 ; k <= n ; k ++){
            for (int i = 1 ; i <= n ; i ++){
                dp2[i] = dp[i] + min (k, i) * x;
            }
            int maxn = 0;
            for (int i = 1 ; i <= n ; i ++){
                maxn = max (dp2[i], maxn);
            }
            cout << maxn << ' ';
        }
        cout << endl;
    }
    return 0;
}

D- Cross Coloring

题目大意:

给一个 n * m 的网格,有 k 种颜色,q 次操作, 每次操作选择一个点,在点所在行列都染成你所选的颜色。每次操作都可以从 k 种颜色中选一种。问在 q 次操作后,存在多少种不同颜色的表格。

分析:

做到这题的时候相当于背水一战了,成了就上蓝了,寄了就掉大分了

一开始没啥思路先去看的 e,感觉 e 更难写,就回过头来看看 d。其实挺简单的,只需要看所有操作后,表格中存在多少种色块就行,记为 c,(先假设每次涂的颜色都不一样)。答案就是 \(k ^ c\)

要注意的是题目只保证了 \(\sum q <= 2e5\) ,没有保证 n 和 m 的,每次清空长度为 n, m会很慢。理论上每次清空长度 n, m 要跑 2e9 次。但是 cf 神机貌似跑过去了。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod = 998244353;
bool x[N], y[N];
typedef pair <int, int> pii;
ll qpow(ll base, ll power) {
    ll result = 1;
    while (power > 0) {
        if (power & 1) {
            result = result * base % mod;
        }
        power >>= 1;
        base = (base * base) % mod;
    }
    return result;
}
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        ll n, m, k, q, cnt = 0; cin >> n >> m >> k >> q;
        for (int i = 1 ; i <= n ; i ++){
            x[i] = 0;
        }
        for (int i = 1 ; i <= m ; i ++){
            y[i] = 0;
        }
        vector<pii> a;
        while (q --){
            int u, v;
            cin >> u >> v;
            a.push_back({u, v});
        }
        for (int i = a.size () - 1 ; i >= 0 ; i --){
            if (!x[a[i].x] || !y[a[i].y]){
                if (!x[a[i].x]){
                    x[a[i].x] = 1;
                    n --;
                }
                if (!y[a[i].y]){
                    y[a[i].y] = 1;
                    m --;
                }
                cnt ++;
                if (!n || !m) break;
            }
        }
        // cout << cnt << endl;
        cout << qpow(k, cnt) << endl;
    }
    return 0;
}
posted @ 2022-02-23 13:58  sweet_guagua  阅读(130)  评论(0)    收藏  举报