HDU 1521
指数型生成函数。做这题时,回去看看组合数学才知道,指数生成函数求的就是多重集合的r排列数。
#include <iostream> #include <cstdio> #include <algorithm> #define N 15 using namespace std; struct PQ{ int p,q; }; PQ c1[N],c2[N]; int num[N]; PQ cal; int Q[N]; int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); } PQ addsum(PQ a,PQ b){ PQ tmp; tmp.q=a.q*b.q; tmp.p=a.p*b.q+a.q*b.p; int g=gcd(max(tmp.p,tmp.q),min(tmp.p,tmp.q)); tmp.p/=g; tmp.q/=g; return tmp; } int main(){ int n,m,ptmp,qtmp; Q[0]=1; for(int i=1;i<N;i++) Q[i]=Q[i-1]*i; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++) scanf("%d",&num[i]); for(int i=0;i<N;i++){ c1[i].p=c2[i].p=0; c1[i].q=c2[i].q=1; } for(int i=0;i<=num[1];i++) c1[i].p=1,c1[i].q=Q[i]; for(int i=2;i<=n;i++){ for(int j=0;j<N;j++){ for(int k=0;k+j<N&&k<=num[i];k++){ ptmp=1,qtmp=Q[k]; cal.p=ptmp*c1[j].p;cal.q=qtmp*c1[j].q; ptmp=gcd(max(cal.p,cal.q),min(cal.p,cal.q)); cal.p/=ptmp; cal.q/=ptmp; c2[k+j]=addsum(cal,c2[k+j]); } } for(int j=0;j<N;j++) c1[j]=c2[j],c2[j].p=0,c2[j].q=1; } printf("%d\n",c1[m].p*Q[m]/c1[m].q); } return 0; }