Codeforces525E -- Anya and Cubes 中途相遇法

本文探讨了一种复杂操作组合下求解数列和优化问题的方法,涉及了深度优先搜索、中途相遇法及动态规划技巧,旨在通过至多k次操作使数列元素之和达到特定目标值s。文章详细介绍了AC代码实现,包括初始化、计数器使用、深度优先搜索策略等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有n个a[0]--a[n-1]。定义一种操作:可以使数a[i]变成它的阶乘,例如5通过操作变成120。对于每一个数,可以选它,或者选它的阶乘,或者不选。要求通过 至多k次操作,使得被选的数的和为s。求方案总个数。

思路:n不超过25,时间限制是2000ms。首先可以肯定是用dfs暴力搜索,但是n又有些大,单纯暴力必然超时。这时就要用到中途相遇法,并将中间结果存下来。

AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <iomanip>
#define debug puts("xxxxxxx")
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 1<<29
typedef long long ll;
using namespace std;
const int maxn=30;
ll a[maxn],b[maxn],sum,ans;
int k,n;
void init()
{
    ans  = 0;
    b[1] = 1;
    for(int i=2; i<19; i++) b[i] = b[i-1]*i;
}
map<int,map<ll,ll> > cnt1;
map<int,map<ll,ll> > cnt2;
map<ll,ll>  ::iterator it;
void dfs1(int now,int t,ll val)
{
    if(now == n/2+1)
    {
        cnt1[t][val] ++;
        return ;
    }
    if(t<=k ) dfs1(now+1,t,val);
    if(t<=k && val+a[now]<=sum)
    {
        dfs1(now+1,t,val+a[now]);
    }
    if(t+1<=k && a[now]<19)
    {
        if(val+b[a[now]]<=sum) dfs1(now+1,t+1,val+b[a[now]]);
    }
    return ;
}
void dfs2(int now,int t,ll val)
{
    if(now==n+1)
    {
        cnt2[t][val] ++;
        return ;
    }
    if(t<=k) dfs2(now+1,t,val);
    if(t<=k && val+a[now]<=sum) dfs2(now+1,t,val+a[now]);
    if(t<k && a[now]<19)
    {
        if(val+b[a[now]]<=sum) dfs2(now+1,t+1,val+b[a[now]]);
    }
    return ;
}
int main()
{
    init();
    cin>>n>>k>>sum;
    for(int i=1; i<=n; i++) cin>>a[i];
    dfs1(1,0,0ll);
    dfs2(n/2+1,0,0ll);
    for(int i=0;i<=k;i++)
    {
        for(int j=0;j<=k;j++)
        {
            if(i+j>k) break;
            for(it = cnt1[i].begin();it!=cnt1[i].end();it++)
            {
                ans += (it->second) * cnt2[j][sum-(it->first)];
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值