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!),也就是说答案为 (inom{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
", C(x + y, x));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Silymtics/p/solution-CF1545B.html