CSP组T1怪物

CSP组T1怪物

题目大意

今有 n n n 只怪物,第 i i i 只怪物的生命值为 a a a。你和另外一位玩家正在合力击杀这些怪物,你的攻击力为 x x x,对方的攻击力为 y y y。你们需要轮流对活着的怪物进行攻击,第一个回合是你的回合。被攻击的怪物将会损失攻击它的玩家攻击力的生命值,若此后它的生命值非正,怪物将会死亡,击杀它的玩家得到 1 1 1 分。当不存在活着的怪物时,游戏结束。在你的回合,你可以选择攻击任意一只怪物,也可以选择不进行攻击。在对方的回合,对方会选择当前存活的,编号最小的怪物进行攻击。你需要合理地安排你的策略,使得你的得分最大,并求出这个得分。

思路过程

首先我一开始的思路就是普通的贪心吗?就是按价值排序,然后取最左边去杀,但是问题其实是在于这个问题?怪物一下砍不掉。就是说如果当前的最小你一剑砍不掉,对方也一剑砍不掉坐左边的怪兽,但是他砍完之后你再去砍就可以获得金币了,同理对方也是一样的道理,所以这道题的思路也就不是一个普通的贪心了。不过贪心的这个思路还是没有错的

设最终在第 i 只怪物上的得分为 x i ∈ 0 , 1 x_i \in {0,1} xi0,1,可以发现:

  • 假如 x i = 0 x_i=0 xi=0,那么我们一定不会对第 i i i 只怪物进行任何攻击。
  • 假如 x 1 = 1 x_1=1 x1=1,那么我们的攻击策略一定是:先进行次数尽量少的攻击,然后在对手攻击若干次后,最后将其一击毙命。

对于第 i 只怪物,你和对手的攻击次数分别为 p i , q i p_i,q_i pi,qi。对两种情况的攻击次数分别计算:

  • x i = 0 x_i=0 xi=0​:完全让对手杀死这只怪物。
    p i , 0 = 0 p_{i,0}=0 pi,0=0

    q i , 0 = ⌊ h i − 1 b ⌋ q_{i,0}=\left \lfloor \frac{h_i-1}{b} \right \rfloor qi,0=bhi1

  • x i = 1 x_i=1 xi=1:进行 r r r 次的攻击后,满足 ( h i − r × a ) % b ∈ [ 1 , a ] (h_i−r \times a) \% b \in \left[1,a\right] (hir×a)%b[1,a],即 ( ( h i − 1 ) − r × a ) ∈ [ 0 , a ) \left(\left(hi−1\right)−r \times a\right) \in \left[0,a\right) ((hi1)r×a)[0,a),从中可以解得最小的 r r r

p i , 1 = r + 1 = ⌊ ( h i − 1 ) % b a ⌋ + 1 p_{i,1}=r+1=\left \lfloor \frac{\left(h_i-1\right) \% b}{a} \right \rfloor +1 pi,1=r+1=a(hi1)%b+1

q i , 1 = ⌊ ( h i − 1 ) − r × a b ⌋ q_{i,1}=\left \lfloor \frac{\left(h_i-1\right)-r \times a}{b} \right \rfloor qi,1=b(hi1)r×a

注意到我们可以跳过若干回合,且不必按顺序攻击,这意味着我们花费在前 i i i 只怪物上的攻击次数至多比对手多 1 1 1 次。记 d i , k = q i , k − p i , k d_{i,k}=q_{i,k}−p_{i,k} di,k=qi,kpi,k,则上述限制为:
∀ i , 1 ∑ k = 1 i ( [ x k = 0 ] d k , 0 + [ x k = 1 ] d k , 1 ) ≥ 0 \forall i,1\sum_{k=1}^{i}\left(\left[x_k=0\right]d_{k,0}+\left[x_k=1\right]d_{k,1}\right) \ge 0 i,1k=1i([xk=0]dk,0+[xk=1]dk,1)0
问题转化为:对于每个 i i i 选择一个 x i = 0 / 1 x_i=0/1 xi=0/1 且使对应的前缀和不小于 0 0 0。由于每种选择方案的 d i d_i di 都是已知的,可以贪心解决。具体地,假如选择 x i = 1 x_i=1 xi=1 后仍然满足条件,那么直接使答案加 1 1 1;否则贪心地将之前(包括当前的 i i i)选择 x j = 1 x_j=1 xj=1 d j , 0 − d j , 1 d_{j,0}−d_{j,1} dj,0dj,1 最大的 j j j 改为 x j = 0 x_j=0 xj=0(由于 d i , 0 d_{i,0} di,0 必然e大于 0 0 0,所以调整之后一定可以满足限制)。整个过程可以使用优先队列维护。

时间复杂度: O ( n log ⁡ ⁡ n ) \mathcal{O}(n \log ⁡n) O(nlogn)

代码部分

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, x, y, a[5000005], yes[5000005], no[5000005];
int ans,sum=1;
signed main() 
{
	cin>>n>>x>>y;
	for(int i=1;i<=n;i++) 
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++) 
	{
		a[i]--;
		int p=(a[i]%y)/x,q=(a[i]-p*x)/y;
		p++;
		yes[i]=q-p;
		no[i]=a[i]/y+1;
	}
	priority_queue<int>monster;
	for (int i=1;i<=n;i++) 
	{
		monster.push(no[i]-yes[i]);
		sum+=yes[i];
		if (sum>=0) 
		{
			ans++;
		} 
		else 
		{
			sum+=monster.top();
			monster.pop();
		}
	}
	cout<<ans<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值