指数型生成函数。做这题时,回去看看组合数学才知道,指数生成函数求的就是多重集合的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;
}