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

CF1545B AquaMoon and Chess

CF1545B AquaMoon and Chess

昨天晚上(今天早上)CF的div2的D題,

不算難,

但是很妙.

(將根據我的思考過程來寫)

首先,

我們發現只有至少兩個1在一起的時候才能動,

一個1是肯定不可能動的,

然後能動的1的數量和不能動的1的數量其實是定了的.

為什麼?

我們把成對的1拿掉,

不管我們以什麼方式拿,

只要把所有成對的1拿掉,

拿掉之後,

這個棋盤就只剩下單個的1和一些0,

然後我們發現我們拿掉的那些成對的不管怎麼放,

都不會改變兩個單個的1之間的0的個數.

也就是無論我們怎麼移,

我們都無法使兩個不相鄰的1相鄰.

所以我們可以移動的1的對數時固定的,

然後我就想,

那我就把所有的成對的1先都拿掉,

在把剩下的棋盤看作一段一段被1分開的0,

這樣就可以計算方案數了.

其實我們不需要分段,

為什麼?

我們想,

如果我們有這樣一段0001000,

我們把一對1放在左邊和放在右邊是不是一樣的,

都是00011000,

所以我們就可以把單個的1拿掉,

只統計0的個數,

這樣問題就轉化成了把這些對1插入到這些0裡面了,

然後問題就很簡單了嘛...

不就是一個組合嘛...

code:

#include <cstdio>
#include <iostream>
using namespace std;
int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)){
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)){
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
typedef long long ll;
const int N = 1e5 + 5, mod = 998244353;
ll fac[N], inv[N];
ll ksm(ll a, int b){
    ll ans = 1;
    while (b){
        if (b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b  >>= 1;
    }
    return ans;
}
ll C(int n, int m){
    if (n < m || m < 0) return 0;
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void init(int n){
    fac[0] = 1;
    for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod;
    inv[n] = ksm(fac[n], mod - 2);
    for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
int t, n, a[N], n1, n2, sum;
int main(){
    t = read();
    init(N - 5);
    while (t--){
        n = read(); n1 = n2 = sum = 0;
        for (int i = 1; i <= n; i++) scanf("%1d", &a[i]);
        for (int i = 1; i <= n; i++){
            if (a[i]) sum++;
            else {
                n1++;
                n2 += (sum >> 1);
                sum = 0;
            }
        }
        if (sum) n2 += (sum >> 1);
        n1++;
        printf("%lld\n", C(n2 + n1 - 1, n1 - 1));
    }
    return 0;
}
看不見我看不見我看不見我