Anya and Cubes - CodeForces 525E - Virtual Judge
思路分析
这个问题主要是考虑怎么降低时间复杂度,先考虑正常用DFS或者BFS进行穷尽搜索需要的时间,每个物体有不选,选,选阶乘值,三个状态,因此时间复杂度可以达到3的25次方
分治思想
对后一半物体进行搜索,最多需要3的13次方时间复杂度,然后得到后半部分的物体的和值,以及当前的使用阶乘的次数,那么,前一部分的和值就是总和值S减去后一半物体的和值,前半部分的使用次数加上后半部分使用阶乘的次数应该小于等于k
对前一半的部分,计算出和值为sum,使用次数为used的状态,有多少种选择情况能达到
对后一半的部分,查看搜索结束时的sum和used,推算出前部分符合条件的和值和使用次数,将前一部分记录过的情况数加入答案方案总数
实现方法与细节
用map<ll,ll> cnt[],cnt[x][s]表示前半部分使用次数为x次,和为s时的选取方案数
因为后半部分涉及到遍历前半部分符合条件的次数,所以应该减少后半部分的搜索花销,若有n个物体,前半部分负责1到n/2+1的计算,后半部分负责n/2+2到n的计算
/*
19!超出了1e16
*/
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
#define ll long long
const int maxn=30;
ll n,k,s,ans;
ll a[maxn],a1[maxn];
map<ll,ll> cnt[30];
ll fact(ll x){
if(x>=19) return 1e16+5;
else {
ll res=1;
for(int i=1;i<=x;i++) {res*=i;}
return res;
}
}
void dfs1(ll idx,ll sum,ll used){
if(sum>s || used>k) return;
if(idx==n/2+2) {
cnt[used][sum]++;
return;
}
//不选
dfs1(idx+1,sum,used);
//选自己
dfs1(idx+1,sum+a[idx],used);
//选阶乘
dfs1(idx+1,sum+a1[idx],used+1);
}
void dfs2(ll idx,ll sum,ll used){
if(sum>s || used>k) return;
if(idx==n+1) {
ll ts=s-sum,tk=k-used; //target_sum, target_k
for(int i=0;i<=tk;i++){
if(cnt[i].count(ts)){ //可以加快程序运行速度
ans+=cnt[i][ts];
//printf("此时ts=%d,tk=%d\n",ts,tk);
}
}
return;
}
//不选
dfs2(idx+1,sum,used);
//选自己
dfs2(idx+1,sum+a[idx],used);
//选阶乘
dfs2(idx+1,sum+a1[idx],used+1);
}
int main()
{
//freopen("D:\\in.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>k>>s;
for(int i=1;i<=n;i++){
cin>>a[i];
a1[i]=fact(a[i]);
}
ans=0;
dfs1(1,0,0);
dfs2(n/2+2,0,0);
cout<<ans<<"\n";
return 0;
}