codeforces 1546D. AquaMoon and Chess | 组合数学

题目链接:~~~


题目大意:
在一个 1 * n 的棋盘中,0 表示没旗子, 1 表示有棋子。
有两个操作:

  1. 把一个棋子(假设在位置 i) 放到 i + 2,如果满足 i+2 <=n 并且 i+1 有棋子和 i + 2 没棋子
  2. 把一个棋子(假设在位置 i) 放到 i - 2,如果满足 i - 2 <=n 并且 i-1 有棋子和 i - 2 没棋子

给出 n 和一个棋盘的初始状态,可以通过这两种操作得到多少种棋局,结果对 998244353 取模


分析:
第一点:这里的 0 和 1 是无区别的(000,三个 0 没有区别
第二点:明显需要 11 才可以进行移动,而单个的 1 不能进行操作,并且单个的 1 对结果无影响
eg:01011 等价于 0011
01011 对应的情况为:01110、11010
0011   对应的情况为: 0110、 1100
也就是说,当 11 移动到一个单个 1 时,11可以抛弃原来的一个 1,和单个的一个 1 捆绑,最后的结果就是,可以忽略单个的 1
第三点:最后的结果就是,0 和 11 进行排列组合,统计 0 和 11 的个数,求一下组合数就好


参考代码:

#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod=998244353;
const int maxn = 1e5 + 5;
using namespace std;		

// 快速幂求逆元
ll pow_mod(ll a, ll b, ll p){    // a 的 b 次方求余 p 
        ll ans = 1;
        while(b){
            if(b & 1) ans = (ans * a) % p;
            a = (a * a) % p;
            b >>= 1;
        }
        return ans;
    }
//分数取余 (a/b) % p = a * (b^-1) % p = a * (b ^ p-2) % p
ll inv(ll a, ll b, ll p){
    return (a * pow_mod(b, p-2, p)) % p;
}
//费马求 a 关于 p 的逆元
ll inv(ll a, ll p){     
    return pow_mod(a, p-2, p);
}

ll fac[200005]; // 阶乘

    //计算组合数 Cmn
ll C(ll m, ll n, ll p){
     return fac[n] * inv(fac[m], p) % p * inv(fac[n-m], p) % p;
}


int main(){
	
	fac[0] = 1;
	for(int i = 1; i < maxn; i++) fac[i] = fac[i-1] * i % mod;
	
	int ncase;
	cin >> ncase;
	
	while(ncase--){
		int n;
		cin >> n;
		string s;
		cin >> s;
		int tot = 0, num = 0, len = 0; char last = '.';
		for(auto i : s){
			if(i == '0'){
				tot++;
				if(i != last){
					tot += len / 2;
					num += len / 2;
					len = 0;
				}
			}
			else{
				if(last == '1') len++;
				else len = 1;
			}
			last = i;
		}
		tot += len / 2;
		num += len / 2;
		cout << C(num, tot, mod) << endl;
	}
	
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值