bzoj 1856: [Scoi2010]字符串

难度:思维题

算法:逆元+组合数学

题解:

图片来源:www.cnblogs.com/Y-E-T-I/p/7384430.html

我们设选1为(1,1),选0为(1,-1)

目标是(n+m,n-m)

总方案数为C(n+m,n),因为有n+m个位置,放n个1

然后要减去不合法的,即通过y=-1的。将线路与y=-1交点的左边沿着y=-1做对称操作,则最后等价于从(0,-2)走到(n+m,n-m)的方案数

所以向上走n-m+2则有

x-y=n-m+2

x+y=n+m

x=n+1,y=m-1

所以不合法方案为C(n+m,n+1)

ans=C(n+m,n)-C(n+m,n+1)

我用的是线性筛逆元,O(n)求解。

注意:最后要(......%mod+mod)%mod!!!

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#define ll long long
#define N 2000005
using namespace std;
const ll p=20100403;
ll inv[N<<1];//一定要开long long 
void invv()
{
	inv[0]=1;
	inv[1]=1;
	for(int i = 2;i <= N;i++)
	{
		inv[i]=(p-p/i)*inv[p%i]%p;
	}
}
ll jc[N];
ll ans1,ans2;
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	invv();
	for (int i = 2;i <= n+m;i++)
	{
		inv[i]=(inv[i]*inv[i-1])%p;
	}
	jc[1]=1;
	for(int i = 2;i <= n+m;i++)
	{
		jc[i]=(jc[i-1]*i)%p;
	}
	ans1=((jc[n+m]*inv[n])%p*inv[m])%p;
	ans2=((jc[n+m]*inv[n+1])%p*inv[m-1])%p;
	printf("%lld\n",(ans1-ans2+p)%p);
	return 0 ;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值