1. 程式人生 > 其它 >cf掉分日記-Educational Codeforces Round 123 (Rated for Div. 2) A - D

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;
}