1. 程式人生 > 其它 >LG 題解 CF1545B AquaMoon and Chess

LG 題解 CF1545B AquaMoon and Chess

題目傳送門

更差的閱讀體驗

Solution

你拿到這個題後開始手模它這個操作。

你發現,對於一個 11 移動的時候就相當於整體左移或者右移。

我們假設讓它右移,如果它右邊是一個 0,那麼它右移就相當於和這個 0 交換位置。如果它右邊是一個 1實際並不能右移,但也可以看做它和這個 1 交換了一下位置。

那不難看出,和 0 交換位置時會產生新的狀態,和 1 交換位置時並不會產生新的狀態。

也不難看出,每一組 11 在整個序列中都是可以自由移動的。那麼我們不妨將每個 11 都劃分成一個整體,對於那些單獨的 1 就直接扔掉。

那麼對於剩下的 110,顯然可以隨便安排他們的位置。

設有 \(x\)11

\(y\)0,總排列數位 \((x+y)!\),因為有重複狀態所以再除以 \(x! y!\),也就是說答案為 \(\binom{x+y}{x}\)

直接預處理一個階乘和逆元就可以 \(\mathcal O(1)\) 計算了。

至於 \(x\)\(y\) 從原串中暴力找就可以。

Code

/*
Work by: Suzt_ilymtics
Problem: 不知名屑題
Knowledge: 垃圾演算法
Time: O(能過)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 2e5+50;
const int INF = 1e9+7;
const int mod = 998244353;

int T, n;
int fac[MAXN], inv[MAXN];
char s[MAXN];

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

void Init() {
    int M = 200000;
    fac[0] = fac[1] = inv[0] = inv[1] = 1;
    for(int i = 2; i <= M; ++i) {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    }
    for(int i = 2; i <= M; ++i) {
        inv[i] = inv[i - 1] * inv[i] % mod; 
    }
}

int C(int n, int m) {
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

signed main()
{
	Init();
    T = read();
    while(T--) {
        n = read();
        cin >> s + 1;
        int y = 0, x = 0;
        for(int i = 1; i <= n; ++i) if(s[i] == '0') y++;
        for(int i = 2; i <= n; ++i) {
            if(s[i] == '1' && s[i - 1] == '1') {
                x++, s[i] = s[i - 1] = '0';
            }
        }
        printf("%lld\n", C(x + y, x));
    }
    return 0;
}