题目描述:
http://community.topcoder.com/stat?c=problem_statement&pm=12644
给了两个数组,第一个的kind[i]对应城市i的类型。第二个为发现的类型,是一个set。
以及一个数字K,给出发现城市的数目。然后问题的那句英文不太好理解,意思其实是可能的发现的这些类型对应的城市都有哪些可能。
由于城市有标号,都是唯一的。所以可以将kind反过来统计,统计某种类型i ,对应的城市数目km[i]。
然后再将found数组扩展为fm,其中fm[i]表示类型i有没有被发现。
然后就是一个在类型上的计数问题了。
记 f (t , k) 为: 在已经确定了[t+1,n)类型的城市可能时。目前还有k个发现的城市没有确定下来,则余下的[0,t]共有多少种可能性?
对第t个类型,如果fm[t]=true ,说明发现了这种类型的城市,则枚举所有发现这种类型的城市的数目x,将问题规约到余下[0,t-1]类型和k-x个城市上。
也即:f (t,k) = sum (C(x,km[t])* f(t-1, k-x))。
而如果fm[t]=false,则发现了这种类型城市0个: f(t,k) = f(t-1,k)
再考虑一些边界条件即可。
一种基于memo的实现如下:
int m,n; class Excavations2 { public: vector <int> km; vector <bool> fm; int K; long long dp[51][51]; long long comb[51][51]; long long Solve(int t,int k){ if (t==-1){ //left none types if (k==0){return 1;} return 0; } if (k==0){//non-discovered cities,but left some types unassigned if (fm[t]){return 0;} } if (dp[t][k]!=-1){return dp[t][k];} long long res=0; if (!fm[t]){ //type t not discovered. k belongs to [0,t-1] types res=Solve(t-1,k); } else{ int maxt=min(km[t],k); //the limit make k>=0 for (int i=1;i<=maxt;i++){ //select i cities from km[t] cites res+=(Comb(km[t],i)*Solve(t-1,k-i)); } } dp[t][k]=res; return res; } long long Comb(int a,int b){ if (a==0){ if (b==0){return 1;} //select 0 from 0 return 0; //select b>0 from 0 elements: no way } if (b==0){ //a!=0 return 1; //select 0 elements } if (comb[a][b]!=-1){return comb[a][b];} long long res=Comb(a-1,b-1)+Comb(a-1,b); comb[a][b]=res; return res; } long long count(vector <int> kind, vector <int> found, int K) { m=kind.size(); int n=*max_element(kind.begin(),kind.end()); km.resize(n,0); //type i has km[i] cities for (int i=0;i<m;i++){ km[kind[i]-1]++; } fm.resize(n,false); //fm[i]: type i has been found for (int i=0;i<found.size();i++){ fm[found[i]-1]=true; } this->K=K; memset(dp,-1,sizeof(dp)); memset(comb,-1,sizeof(comb)); return Solve(n-1,K); } };