codeforces E

 说的是给了n个立方体,立方体从1标号到n,每个立方体上有一个数字, 你有 k 个机会 使得其中 k个数位他们自己的阶乘,(自然使用可以少于k次机会,每个立方体最多被使用1次) ,那么求出你从这n个立方体重选出任意个立方体使得 他们的和为S

n<25

可以知道直接使用n去枚举自然受不了, 我们将n个数字分为两部分来算,前面n/2个数字 我们枚举他们使用j次可以得到的数,然后后面的n-n/2个数再次使用这个方法,直接在dfs枚举的时候进行判断S-s 在前一个钟是否出现过,出现过就加起来。 分块处理 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <map>
 5 #include<cstdio>
 6 using namespace std;
 7 typedef long long LL;
 8 map<LL,int>mp[30];
 9 LL A[30];
10 LL dp[30];
11 LL time[1000000];
12 int n,K;
13 LL S,ans;
14 void dfs(int p, int k, LL s){
15     if(p==n/2){
16          mp[k][s]++;
17     }else{
18         dfs(p+1,k,s);
19         if(s+A[p]<=S)dfs(p+1,k,s+A[p]);
20         if(k+1<=K && A[p]<=18 &&  s+dp[A[p]] <=S ) dfs(p+1,k+1,s+dp[A[p]]);
21     }
22 }
23 void dfs1(int p, int k, LL s){
24     if(p==n){
25          for(int i =0; i+k<=K; i++)
26             if(mp[i].count(S-s)>0) ans+=mp[i][S-s];
27     }else{
28          dfs1(p+1,k,s);
29          if(s+A[p]<=S) dfs1(p+1,k,s+A[p]);
30          if(k+1<=K && A[p]<=18 && s+dp[A[p]]<=S) dfs1(p+1,k+1,s+dp[A[p]]);
31     }
32 }
33 int main()
34 {
35 
36 
37    dp[0]=1;
38    for(LL i=1; i<=18; i++) dp[i]=dp[i-1]*i;
39    ans=0;
40    scanf("%d%d%I64d",&n,&K,&S);
41    for(int i=0; i<n; i++)
42       scanf("%I64d",&A[i]);
43    dfs(0,0,0);
44    dfs1(n/2,0,0);
45    printf("%I64d
",ans);
46     return 0;
47 }
原文地址:https://www.cnblogs.com/Opaser/p/4381974.html