http://codeforces.com/contest/525/problem/E
学习了传说中的折半DFS/双向DFS
先搜前一半数,记录结果,然后再搜后一半数,匹配之前结果。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #include<map> 7 #define LL long long 8 using namespace std; 9 const int mxn=1200000; 10 struct data{ 11 LL x,sum; 12 }b[mxn];// 13 int tot=0; 14 map<LL,LL>mp[30];//用[i]次阶乘,和为[j]的方案数 15 LL n,k,s; 16 LL a[mxn]; 17 LL p[30]; 18 void DFS(LL cnt,LL t,LL now,int ed){ 19 if(now>s || t>k)return; 20 if(cnt>ed){ 21 if(ed==n/2){ 22 tot++; 23 b[tot].x=t; 24 b[tot].sum=now; 25 } 26 else{ 27 mp[t][now]++; 28 } 29 return; 30 } 31 DFS(cnt+1,t,now,ed);//不选 32 DFS(cnt+1,t,now+a[cnt],ed);//选 33 if(a[cnt]<19)DFS(cnt+1,t+1,now+p[a[cnt]],ed);//选阶乘*/ 34 return; 35 } 36 void init(){ 37 p[1]=1; 38 for(int i=2;i<19;i++){ 39 p[i]=p[i-1]*i; 40 } 41 } 42 int main(){ 43 init(); 44 scanf("%I64d%I64d%I64d",&n,&k,&s); 45 int i,j; 46 for(i=1;i<=n;i++)scanf("%d",&a[i]); 47 int mid=n/2; 48 DFS(1,0,0,mid); 49 DFS(mid+1,0,0,n); 50 LL ans=0; 51 for(i=1;i<=tot;i++){ 52 for(j=0;j<=k-b[i].x;j++){//可以不使用阶乘,所以从0开始 53 ans+=mp[j][s-b[i].sum]; 54 } 55 } 56 printf("%I64d ",ans); 57 return 0; 58 }