题目地址:http://www.spoj.com/problems/IE1/
题目大意:n个盒子,每个盒子里有mi颗糖,从每个盒子里取一些糖,要求至少取a颗,至多取b颗,问方案数。n<=10
算法讨论:
对盒子进行容斥,强制某些盒子取mi+1颗糖,然后将剩余的糖分配到n+1个盒子中(因为糖可以不分完,所以多设一个盒子放剩下的糖)。
由隔板法分析可知,将n个等价的球放到m个等价的盒子中,盒子可以为空的方案数为C(n+m-1,m-1)。
发现n较小,所以组合数可以暴力求得,求组合数的同时直接约分即可。
Code:
#include <cstdio>
#define N 10
#define mod 2004
#define V 10000000
using namespace std;
bool v[N+10],f[V+10];
int a,b,n,ans,cnt,m[N+10],p[V+10];
inline int C(int n,int m){
int ans=1;
if (m>n) return 0;
int two=0,thr=0,fiv=0,sev=0;
for (int i=2;i<=m;++i){
for (int j=i;j%2==0;j/=2) two++;
for (int j=i;j%3==0;j/=3) thr++;
for (int j=i;j%5==0;j/=5) fiv++;
for (int j=i;j%7==0;j/=7) sev++;
}
for (int i=n,j=1;j<=m;--i,++j){
int t=i;
for (;t%2==0 && two;t/=2) two--;
for (;t%3==0 && thr;t/=3) thr--;
for (;t%5==0 && fiv;t/=5) fiv--;
for (;t%7==0 && sev;t/=7) sev--;
ans=(long long)ans*t%mod;
}
return ans;
}
void dfs(int k,int cnt,int tot){
if (tot<0) return;
if (k>n){
if (cnt&1) ans=(ans-C(tot+n,n)+mod)%mod;else ans=(ans+C(tot+n,n))%mod;
return;
}
v[k]=0;
dfs(k+1,cnt,tot);
v[k]=1;
dfs(k+1,cnt+1,tot-m[k]-1);
}
int main(){
scanf("%d%d%d",&n,&a,&b);
for (int i=1;i<=n;++i) scanf("%d",&m[i]);
dfs(1,0,b);
dfs(1,1,a-1);
printf("%d\n",ans);
return 0;
}
By Charlie Pan
Aug 25,2014