题意:给你n个数,k个魔法棒,s为所求的数,然后让你找有多少种方法,能够使的这n个数之和为s,其中一个魔法棒可以使的一个数变成他的阶乘。
思路:采用折半搜索,自己太渣。。请看这位大神详解~
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b) for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b) for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v) memset ((t) , v, sizeof(t))
#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 DBG pf("Hi\n")
typedef __int64 ll;
using namespace std;
typedef pair<ll,ll>P;
map<P,ll>a,b;
ll n,k,s;
ll p[30];
ll val[30];
void init()
{
int i;
p[0]=p[1]=1;
FRE(i,2,20)
p[i]=p[i-1]*i;
}
void dfs(ll pos,ll num,ll kk)
{
if (num>s||kk>k) return ;
if (pos>n/2)
{
a[P(num,kk)]++;
return ;
}
dfs(pos+1,num+val[pos],kk);
dfs(pos+1,num,kk);
if (val[pos]<=20)
dfs(pos+1,num+p[val[pos]],kk+1);
return ;
}
void DFS(ll pos,ll num,ll kk)
{
if (num>s||kk>k) return ;
if (pos>n)
{
b[P(num,kk)]++;
return ;
}
DFS(pos+1,num+val[pos],kk);
DFS(pos+1,num,kk);
if (val[pos]<=20)
DFS(pos+1,num+p[val[pos]],kk+1);
return ;
}
int main()
{
ll i,j;
init();
while (~scanf("%I64d%I64d%I64d",&n,&k,&s))
{
a.clear();
b.clear();
FRE(i,1,n)
scanf("%I64d",&val[i]);
dfs(1,0,0);
DFS(n/2+1,0,0);
ll ans=0;
for (map<P,ll>::iterator it=a.begin();it!=a.end();it++)
{
int aa=(*it).first.second;
for (int bb=0;aa+bb<=k;bb++)
{
if (b.count(make_pair(s-(it->first.first),bb)))
ans+=(it->second*b[make_pair(s-(it->first.first),bb)]);
}
}
pf("%I64d\n",ans);
}
return 0;
}