题意:给你n(25)个数,任选几个数 ,你最多可以对任选的几个数中的 K个数进行操作,操作是将 这个数变为它的阶乘,你选出来的数经过操作以后 等于 s的种类数有多少。
解题思路:看到这题的时候没什么思路,想想水一发dp ,dp[i][j][k]<map>,就想到了这个四维的DP,但是显然这是会挂掉的。因为情况太多了,最多有 3^n种。
那么需要是什么方法呢。那就是折半了,因为我们只需要找到一个值, 而全部DP的话会产生太多的值了,而这大部分值都不是我们需要的。所以就把n个数分成两堆去处理,然后用中间值凑出s,这样复杂度就会少很多.
解题代码:
1 // File Name: e.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月27日 星期五 01时21分34秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque> 10 #include<stack> 11 #include<bitset> 12 #include<algorithm> 13 #include<functional> 14 #include<numeric> 15 #include<utility> 16 #include<sstream> 17 #include<iostream> 18 #include<iomanip> 19 #include<cstdio> 20 #include<cmath> 21 #include<cstdlib> 22 #include<cstring> 23 #include<ctime> 24 #define LL long long 25 26 using namespace std; 27 int n ,m ; 28 LL s ; 29 LL a[100]; 30 LL b[100]; 31 map<int,map<LL,LL> > mpa; 32 map<int,map<LL,LL> > mpb; 33 map<LL,LL>::iterator tt; 34 int li; 35 void dfs(int p ,int k,LL v,map<int,map<LL,LL> > &tmp) 36 { 37 //printf("%d %d %I64d\n",p,k,v); 38 if(k > m) 39 return; 40 if(p == li + 1) 41 { 42 tmp[k][v] += 1 ; 43 return; 44 } 45 if(v + a[p] <= s) 46 dfs(p+1,k,v+a[p],tmp); 47 if(a[p] <= 18 && v + b[p] <= s) 48 dfs(p+1,k+1,v+b[p],tmp); 49 dfs(p+1,k,v,tmp); 50 } 51 int main(){ 52 scanf("%d %d %I64d",&n,&m,&s); 53 for(int i = 1;i <= n;i ++) 54 { 55 scanf("%I64d",&a[i]); 56 } 57 sort(a+1,a+1+n); 58 for(int i = 1;i <= n;i ++) 59 { 60 if(a[i] <= 18) 61 { 62 b[i] = 1; 63 for(int j = 1;j <= a[i]; j ++) 64 { 65 b[i] *= j; 66 } 67 } 68 } 69 li = n/2; 70 dfs(1,0,0,mpa); 71 li = n; 72 //puts("***"); 73 dfs(n/2+1,0,0,mpb); 74 LL sum = 0 ; 75 for(int i = 0 ;i <= m;i ++) 76 { 77 for(int j = 0 ;j + i <= m;j ++) 78 { 79 for(tt = mpa[i].begin(); tt != mpa[i].end();tt++) 80 { 81 sum += (mpb[j][s - tt->first]) * (tt->second); 82 // printf("***%d %I64d %I64d %I64d\n",j,s-tt->first,mpb[j][s-tt->first],tt->second); 83 } 84 } 85 } 86 printf("%I64d\n",sum); 87 return 0; 88 }
时间: 2024-10-08 00:39:53