参考链接: http://www.cnblogs.com/qscqesze/p/4371851.html
给你n个数,k个魔法棒,s为所求的数,然后让你找有多少种方法,能够使的这n个数之和为s,其中一个魔法棒可以使的一个数变成他的阶乘
折半搜索
对于每一个数,都有三种策略,拿,不拿,使用魔法棒
那么我们就直接折半搜索然后扔进一个map里面,然后就查询
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
#define eps 1e-8
typedef long long ll;
#define fre(i,a,b) for(i = a; i <b; i++)
#define free(i,b,a) for(i = b; i >= a;i--)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define ssf(n) scanf("%s", n)
#define sf(n) scanf("%d", &n)
#define sff(a,b) scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf printf
#define bug pf("Hi\n")
using namespace std;
#define INF 0x3f3f3f3f
#define N 30
ll a[N],n,k,s;
ll mid;
struct stud{
ll step,result;
}f[1111111];
ll p[20];
ll cnt;
map<ll,ll>mp[30];
void inint()
{
int i,j;
p[0]=1;
p[1]=1;
fre(i,2,20)
p[i]=p[i-1]*i;
}
void dfs(ll pos,ll num,ll va)
{
if(num>k||va>s) return ;
if(pos==mid+1)
{
f[cnt].step=num;
f[cnt++].result=va;
return ;
}
dfs(pos+1,num,va);
dfs(pos+1,num,va+a[pos]);
if(a[pos]<20)
dfs(pos+1,num+1,va+p[a[pos]]);
}
void DFS(ll pos,ll num,ll va)
{
if(num>k||va>s) return ;
if(pos==n+1)
{
mp[num][va]++;
return ;
}
DFS(pos+1,num,va);
DFS(pos+1,num,va+a[pos]);
if(a[pos]<20)
DFS(pos+1,num+1,va+p[a[pos]]);
}
int main()
{
ll i,j;
inint();
while(~scanf("%I64d%I64d%I64d",&n,&k,&s))
{
fre(i,1,n+1)
scanf("%I64d",&a[i]);
fre(i,0,30)
mp[i].clear();
mid=MID(0,n);
cnt=0;
dfs(1,0,0);
DFS(mid+1,0,0);
ll ans=0;
fre(j,0,cnt)
fre(i,0,k-f[j].step+1)
ans+=mp[i][s-f[j].result];
pf("%I64d\n",ans);
}
return 0;
}