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;
}
posted @ 2021-08-22 16:41  sshadows  阅读(47)  评论(0编辑  收藏  举报