您的位置:首页 > 其它

Codeforces 525E Anya and Cubes【折半枚举法+剪枝Dfs】好题~

2016-11-10 13:08 441 查看
E. Anya and Cubes

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

Anya loves to fold and stick. Today she decided to do just that.

Anya has n cubes lying in a line and numbered from 1 to n from
left to right, with natural numbers written on them. She also has kstickers with exclamation marks. We know that the number of stickers
does not exceed the number of cubes.

Anya can stick an exclamation mark on the cube and get the factorial of the number written on the cube. For example, if a cube reads 5, then
after the sticking it reads 5!, which equals 120.

You need to help Anya count how many ways there are to choose some of the cubes and stick on some of the chosen cubes at most kexclamation
marks so that the sum of the numbers written on the chosen cubes after the sticking becomes equal to S. Anya can stick at most one
exclamation mark on each cube. Can you do it?

Two ways are considered the same if they have the same set of chosen cubes and the same set of cubes with exclamation marks.

Input

The first line of the input contains three space-separated integers n, k and S (1 ≤ n ≤ 25, 0 ≤ k ≤ n, 1 ≤ S ≤ 1016) — the
number of cubes and the number of stickers that Anya has, and the sum that she needs to get.

The second line contains n positive integers ai (1 ≤ ai ≤ 109) — the
numbers, written on the cubes. The cubes in the input are described in the order from left to right, starting from the first one.

Multiple cubes can contain the same numbers.

Output

Output the number of ways to choose some number of cubes and stick exclamation marks on some of them so that the sum of the numbers became equal to the given number S.

Examples

input
2 2 30
4 3


output
1


input
2 2 7
4 3


output
1


input
3 1 11 1 1


output
6


Note

In the first sample the only way is to choose both cubes and stick an exclamation mark on each of them.

In the second sample the only way is to choose both cubes but don't stick an exclamation mark on any of them.

In the third sample it is possible to choose any of the cubes in three ways, and also we may choose to stick or not to stick the exclamation mark on it. So, the total number of ways is six.

题目大意:

一共有N个数字,我们可以最多使用K次魔法,一共有多少种方案使其和能够为S、

使用魔法的同时只能对一个数字使用,能够使其变成!ai,就是ai这个数的阶乘。

思路:

1、首先我们观察数据范围,N是<=25的,我们考虑状态压缩,对应压缩成三进制,0表示这个数不拿,1表示这个数拿,2表示这个数拿并且使用魔法。

那么如果我们暴力枚举的话时间复杂度高达O(3^N)是一个非常大的数量级。

那么考虑优化,我们折半枚举,首先处理前半部分,然后处理后半部分。

2、考虑这样一点,那么我们继续求解:

①暴力枚举前半部分的情况,然后将所有小于等于s的解都记录起来。存入map【i】中,表示对应使用了i次魔法的当前和出现的次数。

②暴力枚举后半部分的情况,对应统计map【i】【s-sum】(0<=i<=k-当前使用魔法的次数),累计起来即可。

3、因为map映射计数耗用时间很大,所以我们考虑一些可行性剪枝:

①如果当前枚举的和大于了s,那么终止。

②如果当前枚举的某个数的阶乘大于了s,那么终止。

③因为后半部分累加可行方案数的时候是需要枚举的,所以我们让前半部分枚举的长度稍多于后半部分的长度

Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define ll __int64
int n,k;
ll ss,output;
int vis[100];
ll a[1000];
ll jiecheng[50];
map<ll,int >s[50];
void init()
{
ll sum=1;
for(int i=1;i<=20;i++)
{
sum*=i;
jiecheng[i]=sum;
}
}
void Dfs(int now,int len,int flag)
{
if(now==len)
{
ll sum=0;
int tmp=0;
for(int i=0;i<now;i++)
{
if(vis[i]==0)continue;
if(vis[i]==1)sum+=a[i];
if(vis[i]==2)
{
if(a[i]>20||jiecheng[a[i]]>ss)return ;
sum+=jiecheng[a[i]],tmp++;
}
if(sum>ss)return ;
}
if(flag==0)
{
s[tmp][sum]++;
}
else
{
if(k-tmp>=0)
{
for(int i=0;i<=k-tmp;i++)
output+=s[i][ss-sum];
}
}
return ;
}
vis[now]=2;
Dfs(now+1,len,flag);
vis[now]=1;
Dfs(now+1,len,flag);
vis[now]=0;
Dfs(now+1,len,flag);
}
int main()
{
init();
while(~scanf("%d%d%I64d",&n,&k,&ss))
{
for(int i=0;i<n;i++)
{
scanf("%I64d",&a[i]);
}
output=0;
for(int i=0;i<=n;i++)s[i].clear();
memset(vis,0,sizeof(vis));
Dfs(n/2,n,0);
Dfs(0,n/2,1);
printf("%I64d\n",output);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Codeforces 525E