hdu 3037 Saving Beans http://acm.hdu.edu.cn/showproblem.php?pid=3037 2012-12-8
Lucas 大组合数取模 c(n+m,m)%p p为质数
p为质数
n=a0*p^0+a1*p^1+...+ak*p^k
m=b0*p^0+b1*p^1+...+bk*p^k
c(n,m)=c(a0,b0)*c(a1,b1)*...*c(ak,bk)
inv(x,p)=powmod(x,p-2,p)
View Code
1 #include <cstdio> 2 using namespace std; 3 4 typedef long long LL; 5 const int P=100010; 6 LL fact[P]; 7 void getfact(int p) 8 { 9 fact[0]=1; 10 for(int i=1;i<p;i++) 11 fact[i]=fact[i-1]*i%p; 12 } 13 LL powmod(LL x,LL y,LL p) 14 { 15 LL s=1,t=x; 16 while(y>0) 17 { 18 if(y&1) s=s*t%p; 19 t=t*t%p; 20 y>>=1; 21 } 22 return s; 23 } 24 LL lucas(LL n,LL m,LL p) 25 { 26 LL ans=1; 27 while(n && m) 28 { 29 LL a=n%p, b=m%p; 30 if(a<b) return 0; 31 LL c=fact[a]*powmod(fact[b]*fact[a-b]%p,p-2,p)%p; 32 ans=ans*c%p; 33 n/=p; m/=p; 34 } 35 return ans; 36 } 37 int main() 38 { 39 int T; 40 scanf("%d",&T); 41 while(T--) 42 { 43 int n,m,p; 44 scanf("%d%d%d",&n,&m,&p); 45 getfact(p); 46 int ans=(int)lucas(n+m,m,p); 47 printf("%d\n",ans); 48 } 49 return 0; 50 }
hdu 4373 Mysterious For http://acm.hdu.edu.cn/showproblem.php?pid=4373 2012-12-8
for a0=0 to n for a1=a0+1 to n ... for am=a(m-1)+1 to n s++; s加了c(n,m)次 刚好遍历所有组合
所以for a0=0 to n for a1=a0 to n ... for am=a(m-1) to n s++; s加了c(n+m,m)次
分解质因数求组合数 364875103=97*3761599不能求逆元
View Code
1 #include <cstdio> 2 #include <map> 3 using namespace std; 4 5 typedef long long LL; 6 const int md=364875103; 7 map<int,int> mp; 8 LL c(LL n,LL m,LL p) 9 { 10 mp.clear(); 11 for(int k=1;k<=m;k++) 12 { 13 int x=n-k+1; 14 for(int i=2;i*i<=x;i++) 15 for(;x%i==0;x/=i) mp[i]++; 16 if(x>1) mp[x]++; 17 x=k; 18 for(int i=2;i*i<=x;i++) 19 for(;x%i==0;x/=i) mp[i]--; 20 if(x>1) mp[x]--; 21 } 22 LL s=1; 23 for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++) 24 { 25 int a=it->first,c=it->second; 26 for(int i=0;i<c;i++) s=s*a%p; 27 } 28 return s; 29 } 30 int main() 31 { 32 int T,C=0; 33 scanf("%d",&T); 34 while(T--) 35 { 36 int n,m; 37 scanf("%d%d",&n,&m); 38 int a[20],k; 39 scanf("%d",&k); 40 for(int i=0;i<k;i++) scanf("%d",&a[i]); 41 a[k]=m; 42 LL ans=1; 43 for(int i=1;i<=k;i++) 44 ans=ans*c(n+a[i]-a[i-1]-1,a[i]-a[i-1],md)%md; 45 printf("Case #%d: %d\n",++C,(int)ans); 46 } 47 return 0; 48 }
hdu 4930 Number Sequence http://acm.hdu.edu.cn/showproblem.php?pid=4390
大意:a1*a2*...*an=b1*b2*...*bn,给出n和b,求a的方案数(ai>1)
容斥原理,分解质因数,map,将m件物品放入n个盒子,盒子可以为空的方案数为c(n-1+m,n-1) 插板法 类似与x1+x2+...+xn=m的方案数
View Code
1 #include <cstdio> 2 #include <map> 3 using namespace std; 4 5 typedef long long LL; 6 const int N=41; 7 const int md=(int)(1e9+7.5); 8 map<int,int> pri; 9 int c[N][N]; 10 void getc() 11 { 12 c[0][0]=1; 13 for(int i=1;i<N;i++) 14 { 15 c[i][0]=c[i][i]=1; 16 for(int j=1;j<i;j++) 17 c[i][j]=(c[i-1][j-1]+c[i-1][j])%md; 18 } 19 } 20 void add(int x) 21 { 22 for(int i=2;i*i<=x;i++) 23 { 24 while(x%i==0) 25 { 26 pri[i]++; 27 x/=i; 28 } 29 } 30 if(x>1) pri[x]++; 31 } 32 int put(int n) 33 { 34 LL s=1; 35 for(map<int,int>::iterator it=pri.begin();it!=pri.end();it++) 36 { 37 int cnt=it->second; 38 s=s*c[n-1+cnt][n-1]%md; 39 } 40 return s; 41 } 42 int main() 43 { 44 int n; 45 getc(); 46 while(~scanf("%d",&n)) 47 { 48 pri.clear(); 49 for(int i=0;i<n;i++) 50 { 51 int b; 52 scanf("%d",&b); 53 add(b); 54 } 55 int ans=0; 56 for(int i=n,sign=1;i>0;i--,sign=-sign) 57 { 58 LL s=put(i); 59 ans=((LL)ans+c[n][i]*s*sign)%md; 60 } 61 ans=(ans+md)%md; 62 printf("%d\n",ans); 63 } 64 return 0; 65 }