Anya and Cubes分析

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值