BZOJ 1856 [SCOI2010]生成字符串 (组合数)
题目大意:给你n个1和m个0,你要用这些数字组成一个长度为n+m的串,对于任意一个位置k,要保证前k个数字中1的数量大于等于0的数量,求所有合法的串的数量
答案转化为所有方案数-不合法方案数
所有方案数显然是
现在比较易懂的解法是转化进坐标系
从(0,0)开始,填1视为向右上↗走,填0视为向右下↘走,如果路径经过了y=-1这条直线,说明不合法
把一个经过y=-1的路径的左半部分(即在路径和y=-1交点之前的那部分路径)关于y=-1翻转
因为是从(0,0)出发,现在变成了从(0,-2)出发,求方案数,显然是
所以最终答案是
求逆元即可
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N 2000100 6 #define mod 20100403 7 #define ll long long 8 using namespace std; 9 10 int n,m; 11 ll mu[N],inv[N]; 12 13 void get_mu() 14 { 15 mu[0]=mu[1]=inv[0]=inv[1]=1; 16 for(ll i=2;i<=n+m;i++) 17 mu[i]=mu[i-1]*i%mod, 18 inv[i]=(mod-mod/i)*inv[mod%i]%mod; 19 for(ll i=2;i<=n+m;i++) 20 inv[i]=inv[i]*inv[i-1]%mod; 21 } 22 23 int main() 24 { 25 scanf("%d%d",&n,&m); 26 get_mu(); 27 ll ans1=mu[n+m]*inv[n]%mod*inv[m]%mod; 28 ll ans2=mu[n+m]*inv[n+1]%mod*inv[m-1]%mod; 29 printf("%lld\n",(ans1-ans2+mod)%mod); 30 return 0; 31 }