HDU 3398 String
题目大意:一个长为n的01字符串,使前缀任意0的数量不大于1的数量,求方案数……
题解:高一模拟赛时做过,是卡特兰数的几何意义,将字符串变为矩阵寻路,不可越过对角线,那么就是卡特兰数了,C(n+m, n)-C(n+m,n+1)=(n+1-m)(n+m)!/(n+1)!m!。需要注意的是取模的问题,如果用高精度最后取模会太慢了,会超时,所以直接用power定理分解素数,对于每个素数分别算幂,取模相乘即可。
#include <cstdio> #include <cstring> const int N=1000001; using namespace std; typedef long long LL; int pri[N*2+1],p[N*2+1],tot; int cal(int pr,int n){int rs=0;while(n)n/=pr,rs+=n;return rs;} void initp(){ memset(pri,0,sizeof pri); tot=0; for(int i=2;i<=N*2;i++){ if(pri[i])continue; p[tot++]=i; for(int j=i*2;j<=N*2;j+=i)pri[j]=1; } } int main(){ int cas,n,m; initp(); scanf("%d",&cas); while(cas--){ scanf("%d%d",&n,&m); LL rs=1; int nm=n-m+1; for(int i=0;i<tot&&p[i]<=n+m;i++){ int cnt=0; while(nm%p[i]==0)nm/=p[i],cnt++; int ipow=cnt+cal(p[i],n+m)-cal(p[i],n+1)-cal(p[i],m); for(int j=1;j<=ipow;j++){ rs=(rs*p[i])%20100501; } } printf("%lld\n",rs); } return 0; }
愿你出走半生,归来仍是少年