根据题意的话每次递归分3种情况
一共最多25个数,时间复杂度为3^25,太大了
我们可以分2次求解第一次求一半的结果,也就是25/2 = 12,记录结果
之后利用剩余的一半求结果 s-结果 = 之前记录过的结果 就可以
时间复杂度降低为 3 ^ (n/2+1)
题目链接:http://codeforces.com/contest/525/problem/E
#include<set>
#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn = 33;
set<LL>vis;
map<LL,int>cnt[maxn];
int n,kk,a[maxn];
LL ans = 0;
LL vk[20],s;
void dfs1(int now,int v,int k,LL value){
if(value > s) return;
if(now == v){
vis.insert(value);
cnt[k][value]++;
return;
}
int e = a[now];
if(e <= 18 && k < kk)
dfs1(now + 1,v,k + 1,value + vk[e]);
dfs1(now + 1,v,k,value + (LL)e);
dfs1(now + 1,v,k,value);
return;
}
void dfs2(int now,int v,int k,LL value){
if(value > s) return;
if(now == v){
LL z = s - value;
if(vis.count(z)){
int _k = kk - k;
for(int i = 0; i <= _k; i++)
ans += cnt[i][z];
}
return;
}
int e = a[now];
if(e <= 18)
dfs2(now + 1,v,k + 1,value + vk[e]);
dfs2(now + 1,v,k,value + (LL)e);
dfs2(now + 1,v,k,value);
}
int main(){
vk[0] = 1;
for(int i = 1; i <= 18; i++) vk[i] = vk[i - 1] * i;
scanf("%d%d%I64d",&n,&kk,&s);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
dfs1(0,n/2,0,0L);
dfs2(n/2,n,0,0L);
printf("%I64d\n",ans);
return 0;
}