CodeCraft-19 and Codeforces Round #537 (Div. 2)C. Creative Snap(递归+二分+思维)

本文解析了CodeForces竞赛中一道关于复仇者位置的题目,通过递归和区间查询优化算法,实现了寻找毁灭所有位置的最小代价。关键在于正确处理无人、有人以及分段情况,并利用排序和二分搜索技巧确定区间内的人数。

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

题目链接:https://codeforces.com/contest/1111/problem/C

 

题目大意:有一堆复仇者在不同的位置上,刚开始有2^n个位置,每次可以分成相等的两部分,如果其中不包含复仇者,毁灭这一部分需要A,如果包含,那就是B*长度*复仇者人数,问毁灭所有位置最小代价

 

题目思路:首先很容易想到每个位置一定只要三种情况,第一、没有人了返回A,这种情况很明显,在没有人的情况下越分越亏,所以遇到没人肯定直接返回A,第二,左右两部分都有人,那么假设一共k人,左边有x人,那么分开后有2^(n-1)*B*x+2^(n-1)*B*(k-x)=2^(n-1)*B*k必x小于2^n*B,所以左右两部分有人一定是分开好,还有一种情况是左边有人右边没人,这样就是看分开来好还是不分开来好。其实到这里最关键的其实是得到区间内的人数,这也将决定我们接下来的操作。如果没人了,那就返回A,如果还有人,那就先算不分需要的代价,如果还可以继续分,那就继续递归。如何得到人数?直接对位置进行排序,得到大于r的位置和大于等于l的位置相减即可。当时没往人数这个方向想跑偏了于是一直没想出来,以后还是得多注意一些看似不重要的量。

 

以下是代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
using namespace std;
const ll MAXN = 1e5+5;
ll a[MAXN],n,k,A,B;
ll dfs(ll l,ll r){
    ll num=upper_bound(a+1,a+k+1,r)-lower_bound(a+1,a+k+1,l);
    if(num==0)return A;
    ll mid=(l+r)>>1;
    ll ans=B*(r-l+1)*num;
    if(l!=r)ans=min(ans,dfs(l,mid)+dfs(mid+1,r));
    return ans;
}
int main()
{
    while(~scanf("%I64d%I64d%I64d%I64d",&n,&k,&A,&B)){
        rep(i,1,k)scanf("%I64d",&a[i]);
        sort(a+1,a+k+1);
        ll ans=dfs(1,1<<n);
        printf("%I64d\n",ans);
    }
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值