Input:
6 10 2 9 6 2 9 6 1 9 4 1 9 5 1 9 10 3 9
Output:
2 4 1 1 0 12
http://www.codechef.com/COOK55/problems/WORLDCUP
组合和0-l的组合累加都要先打好表,不然会超时。
#include <bits/stdc++.h> using namespace std; #define M 1000000007 long long int f[302],fi[302],com[302][302],wsum[302][302]; long long int p(long long int a,long long b){ long long int res=1; while(b){ if(b&1) res=(res*a)%M; b/=2; a=(a*a)%M; } return res; } long long int C(long long int n,long long int r){ return (f[n]*((fi[n-r]*fi[r])%M))%M; } int main(){ long long int t,i,j,n,r,b,l,ans,rr,n6,n4,wb; cin>>t; f[0]=1; for(i=1;i<=300;i++) f[i]=(f[i-1]*i)%M; fi[300]=p(f[300],M-2); for(i=300;i>0;i--) fi[i-1]=(i*fi[i])%M; for(i=0;i<=300;i++) for(j=0;j<=i;j++) com[i][j]=C(i,j); //组合 for(i=0;i<=300;i++){ wsum[i][0]=com[i][0]; for(j=1;j<=i;j++) wsum[i][j]=(wsum[i][j-1]+com[i][j])%M; //0-l累加组合 } while(t--){ ans=0; cin>>r>>b>>l; if((r>1800)||(r < 4 && r > 0) || (((r/6)+((r%6)/4))> b )|| r&1) ans=0; else if(r==0){ if(b<l) l=b; ans=wsum[b][l]; } else{ n6=r/6; for(i=n6;i>=0;i--){ rr=r-(i*6); if(((rr%4)==0) && ((b-i)*4>=rr)){ n4=rr/4; wb=b-i-n4; wb=(wb<=l?wb:l); ans=(ans+(((com[b][i]*com[b-i][n4])%M)*wsum[b-i-n4][wb])%M)%M; } if(rr > (b-i)*4) break; } } cout<<ans<<endl; } return 0; }DP版本:
#include<bits/stdc++.h> using namespace std; long long dp[2000][301][10]={0}; int main(int argc, char const *argv[]) { int i,j,k; dp['0'+0][1][0]=dp['0'+0][1][1]=dp['0'+4][1][0]=dp['0'+6][1][0]=1; for(j=2;j<=300;j++) { for(i='0'+0;i<='0'+6*j;i++) for(k=0;k<10;k++) { dp[i][j][k]=dp[i-6][j-1][k]+dp[i-4][j-1][k]+dp[i][j-1][k]; if(k) dp[i][j][k]+=dp[i][j-1][k-1]; //第j位打门出局 while(dp[i][j][k]>=1000000007) dp[i][j][k]-=1000000007; } } int t,r,b,w; long long ans; cin>>t; while(t--) { scanf("%d %d %d",&r,&b,&w); if(r>6*b) puts("0"); else { ans=0; for(;w>=0;w--) ans+=dp['0'+r][b][w]; printf("%d\n",ans%1000000007); } } return 0; }