难度:思维题

算法:逆元+组合数学

题解:

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

bzoj 1856: [Scoi2010]字符串

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

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

总方案数为bzoj 1856: [Scoi2010]字符串,因为有n+m个位置,放n个1

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

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

bzoj 1856: [Scoi2010]字符串

bzoj 1856: [Scoi2010]字符串

bzoj 1856: [Scoi2010]字符串

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

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

我用的是线性筛逆元,bzoj 1856: [Scoi2010]字符串求解。

注意:最后要(......%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 ;
} 

 

相关文章: