2022 PCCA Winter Camp div 1

這次跟 $\text{KenIsGenius}$ 組隊參加了 $\text{2022 PCCA Winter Camp div 1}$ 的比賽,以下是有解出來的部分。如果是我有解的我會附大意和想法。



$\text{pA.}$ Aibohphobia

題目:給一個字串 $S$ 每次可以選一個子字串 $t$,可以將 $S$ 中不重疊的區間,而且此區間等於 $t$,換成一字元,問最後可以為回文的最長長度。

解法:可以用 $\text{Greedy}$,就是從兩側慢慢往裡面看,用 $\text{Hash}$ 即可快速判斷。

$\text{Code by becaido:}$

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;

#define int long long
#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1e6 + 5;
const int base = 137;
const int MOD = 1e9 + 9;

string s;
int n;
int pro[SIZE], inv[SIZE], pre[SIZE];

int turn (int x) {
    x %= MOD;
    return (x < 0 ? x + MOD : x);
}

int hs (int l, int r) {
    return turn ( (pre[r] - pre[l - 1]) * inv[l - 1]);
}

int power (int d, int up) {
    int ans = 1;
    while (up) {
        if (up & 1)
            ans = ans * d % MOD;
        d = d * d % MOD;
        up >>= 1;
    }
    return ans;
}

int ans = 0;

void cal (int l, int r) {
    if (l > r)
        return;
    if (l == r) {
        ans++;
        return;
    }
    for (int i = 1; i <= (r - l + 1) / 2; i++) {
        if (hs (l, l + i - 1) == hs (r - i + 1, r)) {
            ans += 2;
            cal (l + i, r - i);
            return;
        }
    }
    ans++;
}

void solve() {
    getline (cin, s);
    n = s.size(), s = " " + s;
    pro[0] = inv[0] = 1;
    FOR (i, 1, n) {
        pro[i] = pro[i - 1] * base % MOD;
        inv[i] = power (pro[i], MOD - 2);
        pre[i] = (pre[i - 1] + 1ll * s[i] * pro[i]) % MOD;
    }
    cal (1, n);
    cout << ans << '\n';
}

int32_t main() {
    ios::sync_with_stdio (false), cin.tie (0);
    int tt = 1;
    //cin >> tt;
    while (tt--)
        solve();
}


題目:給一個棋盤,有黑白灰色,灰色各有 $\frac{1}{2}$ 機率會變黑或白色。最後棋盤會有美麗值,如果 $color(x,y) = color(x+1,y-1)$,美麗值等於 $0$,否則美麗值等於用最少骨牌蓋滿整個棋盤,骨牌的定義是相鄰格子必須為異色。問最後美麗值期望值 $\frac{P}{Q}$,輸出 $P\times Q^{-1} \text{mod}\ 998244353$

解法:沿著斜線 $\text{DP}$,好難寫...

$\text{Code by becaido:}$

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1e6 + 5;
const int MOD = 998244353;

int n, m;
string s[SIZE];

int power (int d, int up) {
    int ans = 1;
    while (up) {
        if (up & 1)
            ans = ans * d % MOD;
        d = d * d % MOD;
        up >>= 1;
    }
    return ans;
}

bool check (int sum) {
    int x = 0;
    for (int i = min (n, sum - 1), j = sum - i; i >= 1 && j <= m; i--, j++) {
        if (s[i][j] == 'W')
            x |= (i % 2 ? 2 : 1);
        if (s[i][j] == 'B')
            x |= (i % 2 ? 1 : 2);
        if (x == 3)
            return 0;
    }
    return 1;
}

int ty (int sum) {
    for (int i = min (n, sum - 1), j = sum - i; i >= 1 && j <= m; i--, j++) {
        if (s[i][j] == 'W')
            return (j % 2 ? 0 : 1);
        if (s[i][j] == 'B')
            return (j % 2 ? 1 : 0);
    }
    return 2;
}

int cnt (int sum) {
    int re = 0;
    for (int i = min (n, sum - 1), j = sum - i; i >= 1 && j <= m; i--, j++) {
        re += s[i][j] == '?';
    }
    return re;
}

int all = 1;
int dp[2][2];/// 0 : W 1 : B at i%2==1
int ok[2][2];

void solve() {
    cin >> n >> m;
    FOR (i, 1, n) cin >> s[i], s[i] = " " + s[i];
    FOR (i, 2, n + m) {
        if (!check (i)) {
            cout << "0\n";
            return;
        }
    }
    if (s[1][1] == 'W')
        dp[0][0] = 1, ok[0][0] = 1;
    else if (s[1][1] == 'B')
        dp[0][1] = 1, ok[0][1] = 1;
    else {
        dp[0][0] = dp[0][1] = 1;
        ok[0][0] = ok[0][1] = 1;
        all=2;
    }
    FOR (i, 3, n + m) {
        int t = ty (i);
        dp[i & 1][0] = dp[i & 1][1] = 0;
        ok[i & 1][0] = ok[i & 1][1] = 0;
        if (t == 0 || t == 2) {
            ok[i & 1][0] = ok[! (i & 1)][0] + ok[! (i & 1)][1];
            dp[i & 1][0] += dp[! (i & 1)][0] + ok[! (i & 1)][0] * (i <= n + 1);
            dp[i & 1][0] += dp[! (i & 1)][1] + ok[! (i & 1)][1] * (i <= m + 1);
        }
        if (t == 1 || t == 2) {
            ok[i & 1][1] = ok[! (i & 1)][0] + ok[! (i & 1)][1];
            dp[i & 1][1] += dp[! (i & 1)][0] + ok[! (i & 1)][0] * (i <= m + 1);
            dp[i & 1][1] += dp[! (i & 1)][1] + ok[! (i & 1)][1] * (i <= n + 1);
        }
        dp[i & 1][0] %= MOD;
        dp[i & 1][1] %= MOD;
        ok[i & 1][0] %= MOD;
        ok[i & 1][1] %= MOD;
        all = all * power (2, cnt (i)) % MOD;
    }
    cout << (dp[ (n + m) & 1][0] + dp[ (n + m) & 1][1]) * power (all, MOD - 2) % MOD << '\n';
}

int32_t main() {
    ios::sync_with_stdio (false), cin.tie (0);
    int tt = 1;
    //cin >> tt;
    while (tt--)
        solve();
}

$\text{pD.}$ DVD Player

題目:一個半徑為 $r$ 的 $\text{DVD}$ 在長寬為 $n,m$ 的電視移動,中心點起始座標在 $(x,y)$,$x$ 方向速率為 $V_x$,$y$ 方向速率為 $V_y$,碰到牆壁會反彈,問碰到角落最小時間 $t$,或是不可能。

解法:可以先將 $\text{DVD}$ 變成一個點,就是將 $n-2\times r, m-2\times r ,x-r, y-r$,令 $(x+V_xt, y+V_yt) = (k_1n, k_2m)$,$k_1,k_2$ 為非負整數。可得 $t = (k_1n - x) / V_x = (k_2m - y) / V_y$,將兩邊弄來弄去,可得 $Ak_1+Bk_2=C$,如果 $C$ 不能被 $gcd(A,B)$ 整除,就代表永遠碰不到,否則將 $A,B,C$ 同除 $gcd(A,B)$,兩邊對 $A$ 取 $\text{mod}$,得 $Bk_1 ≡ C (\text{mod}\ A)$,$k_1 ≡ C\times B^{-1}$,用 $\text{exgcd}$ 就可以了,之後再輸出 $t$。然後我用 $\text{__int128}$ 避免溢位。

$\text{Code by becaido:}$

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;

#define int long long
#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

int turn (__int128 x, int mod) {
    x %= mod;
    return (x < 0 ? x + mod : x);
}

void exgcd (int a, int b, int &A, int &B, int mod) {
    if (b == 0)
        return;
    exgcd (b, a % b, A, B, mod);
    int t = A;
    A = B;
    B = turn (t - (__int128) a / b * B, mod);
}

void solve() {
    int n, m, r, x, y, vx, vy;
    cin >> n >> m >> r >> x >> y >> vx >> vy;
    n -= 2 * r, m -= 2 * r;
    x -= r, y -= r;
    int A = vy * n, B = vx * m, C = -vy * x + vx * y;
    int gcd = __gcd (A, B);
    if (C % gcd) {
        cout << "-1\n";
        return;
    }
    A /= gcd, B /= gcd, C /= gcd;
    C = turn (C, A);
    int aa = 0, bb = 1;
    exgcd (B, A, bb, aa, A);
    int k = turn ( (__int128) C * bb, A);
    cout << fixed << setprecision (10) << ( (double) k * m - y) / vy << '\n';
}

int32_t main() {
    ios::sync_with_stdio (false), cin.tie (0);
    int tt = 1;
    //cin >> tt;
    while (tt--)
        solve();
}

$\text{pE.}$ Elise Loves Drinks

$\text{Code by KenIsGenius:}$

#include <bits/stdc++.h>
#define V vector
#define F first
#define S second
#define vi V<int>
#define vvi V<vi>
#define pii pair<int,int>
#define vpii V<pii>
#define pb push_back
#define mp make_pair
#define lowbit(x) (x)&(-x)
#define sqr(x) ((x)*(x))
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define sz(x) (int)((x).size())
#define ld long double
#define StarBurst ios_base::sync_with_stdio(0),cin.tie(0);
#define inf INT64_MAX
#define eps (1e-9)
#define int long long
using namespace std;

signed main(){
    StarBurst
    int n,m;
    cin>>n>>m;
    vi dp(n+1,0);
    vi t(n),a(n);
    int sum=0,s2=0;
    for(int i=0;i<n;i++){
        cin>>t[i]>>a[i];
        if(t[i]==0)dp[i+1]=dp[i]+10-a[i]/10;
        else dp[i+1]=dp[i]-a[i]/10,s2+=a[i];
        sum+=a[i];
    }
    if(sum>m*100){
        cout<<"-1\n";
        return 0;
    }
    for(int i=1;i<=n;i++){
        if(dp[i]<0){
            cout<<"-1\n";
            return 0;    
        }
    }
    cout<<(m*100-sum)/100<<'\n';
}

$\text{pH.}$ Hex Activation Key

題目:有 $16$ 個 $16$ 進制的字元,給一些限制,有 $c_1, c_2$ 不能相鄰,還有 $c_1$ 不能被 $c_2, c_3$ 夾,問要造一個長度為 $n$ 的字串有幾種方法。

解法:可以用 $dp$,$n = 1$ 時特判,否則 $O(16^3\times n)$。

$\text{Code by becaido & KenIsGenius:}$

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int mod = 998244353;
const int MOD = mod;

int dp[2][16][16];/// (pos&1) c[pos-1] c[pos] ways
bool ok[16][16][16];/// c[pos-2] c[pos-1] c[pos] can?
bool o[16][16];

int turn (char c) {
    if (c >= '0' && c <= '9')
        return c - '0';
    return c - 'a' + 10;
}

void solve() {
    int n, m;
    cin >> n >> m;
    if (n == 1) {
        cout << "16\n";
        return;
    }
    while (m--) {
        char c;
        cin >> c;
        if (c == '-') {
            char s[2];
            FOR (i, 0, 1) cin >> s[i], s[i] = turn (s[i]);
            FOR (i, 0, 15) ok[i][s[0]][s[1]] = ok[i][s[1]][s[0]] = 1;
            FOR (i, 0, 15) ok[s[0]][s[1]][i] = ok[s[1]][s[0]][i] = 1;
            o[s[0]][s[1]] = o[s[1]][s[0]] = 1;
        } else {
            char s[3];
            FOR (i, 0, 2) cin >> s[i], s[i] = turn (s[i]);
            ok[s[1]][s[0]][s[2]] = ok[s[2]][s[0]][s[1]] = 1;
        }
    }
    FOR (i, 0, 15) FOR (j, 0, 15) {
        o[i][j] ^= 1;
        dp[0][i][j] += o[i][j];
        FOR (k, 0, 15) ok[i][j][k] ^= 1;
    }
    FOR (t, 3, n) FOR (i, 0, 15) FOR (j, 0, 15) {
        dp[t & 1][j][i] = 0;
        FOR (k, 0, 15) dp[t & 1][j][i] += dp[! (t & 1)][k][j] * ok[k][j][i];
        dp[t & 1][j][i] %= MOD;
    }
    int ans = 0;
    FOR (i, 0, 15) FOR (j, 0, 15) ans += dp[n & 1][j][i];
    cout << ans % MOD << '\n';
}

int32_t main() {
    ios::sync_with_stdio (false), cin.tie (0);
    int tt = 1;
    //cin >> tt;
    while (tt--)
        solve();
}

$\text{pK.}$ Kore wa FFT desu ka?

$\text{Code by KenIsGenius:}$

#include <bits/stdc++.h>
#define V vector
#define F first
#define S second
#define vi V<int>
#define vvi V<vi>
#define pii pair<int,int>
#define vpii V<pii>
#define pb push_back
#define mp make_pair
#define lowbit(x) (x)&(-x)
#define sqr(x) ((x)*(x))
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define sz(x) (int)((x).size())
#define ld long double
#define StarBurst ios_base::sync_with_stdio(0),cin.tie(0);
#define inf INT64_MAX
#define eps (1e-9)
#define int long long
using namespace std;

signed main(){
    StarBurst
    int t;
    cin>>t;
    while(t--){
        int n,p;
        cin>>n>>p;
        int f=0;
        for(int i=0;i<31;i++){
            if((1<<i)>n and (p-1)%(1<<i)==0){
                f=1;
            }
        }
        cout<<(f?"YES\n":"NO\n");
    }
}

我的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$,歡迎追蹤!

留言

熱門文章