题解:P14520 【MX-S11-T1】战争游戏

· · 题解

写作背景

蒟蒻第一篇题解,代码改了十几次,码风不是很好烦请各位谅解。如果有错误或者更优的写法,欢迎大佬们指出!!! 蒟蒻在此感激不尽%%%orz

题意分析

阅读题目,找出以下关键点:

1. 假如你是小L/小K,为了尽可能地攻下对方的城市,你会怎么做呢?

结合题意不难发现交战发生在边界,于是我们想到不惜一切代价将兵力集中在边界

尽管刚开始时对方兵力可能会占优势,但是在我方士兵人数完全充足 (这里有说法的) 的情况下,对方兵力会被快速消耗殆尽。

由此可以看出,如果初始状态下一方总兵力占绝对优势,他总能获胜。

于是我们可以用前缀和表示双方初始地盘内的总兵力。

for (int i=1;i<=n;i++) {
        cin >> city[i];
        sum[i]=sum[i-1]+city[i];
    }
int sum_l=sum[m],sum_r=sum[n]-sum[m];

2. 假如你是生性多疑的小L,你预先不知道小K的兵力比你大/小多少, ,你该如何防患于未然

贪心的你不择手段地扩充自己的兵力。你想到了在符合规则的条件下先手攻占小K的城市。一方面使自己的初始兵力增大,另一方面使小K的初始兵力减少,最大化自己的赢面

3. 钓鱼执法

神机妙算的你猜透了小K的心思,担心小K来一手 “欲擒故纵”,再 “关门打狗”。而让你先手攻占他的一个城市只是障眼法,其实更强的兵力还在后头等着你。

一旦你中计,那么将陷入万劫不复之境。

于是你学会了走一步看十步,先攻下对方一城,如果后面会被对方兵力反噬,那么就撤回操作

(落子无悔)

反之,如果对方没有设下圈套,那就享受饕餮盛宴吧()

于是你设计出了代码如下:

if (l>r&&m<=n-2){
            sum_l=sum[m+1],sum_r=sum[n]-sum[m+1],l=city[m]+city[m+1],r=city[m+2];
            if (r>l) sum_l=sum[m],sum_r=sum[n]-sum[m];
        }

注意:

说了这么多,给大家奉上AC代码。

改过许多次,其中有些表述可以简化,看着比较难受,烦请大家多多包涵

#include <bits/stdc++.h>
#define int long long
#define N 100015
using namespace std;
int t, n;
int city[N], sum[N];
void solve(){
    cin >> n;
    for (int i=1;i<=n;i++) {
        cin >> city[i];
        sum[i]=sum[i-1]+city[i];
    }
    int m=1;
    while (m<n){
        int l=city[m], r=city[m+1];
        int sum_l=sum[m],sum_r=sum[n]-sum[m];
        if (l>r&&m<=n-2){//只有m<=n-2时才有必要判断是否先吞并,否则会越界
            sum_l=sum[m+1],sum_r=sum[n]-sum[m+1],l=city[m]+city[m+1],r=city[m+2];
            if (r>l) sum_l=sum[m],sum_r=sum[n]-sum[m];//依题意,两人的操作一定是最优的,所以这里判断出有被吃掉的风险就应该撤回操作,而不是傻乎乎地被对面吃掉
        }
        if (sum_l>sum_r) cout << 1;
        else cout << 0;
        m++;
    }
    cout << endl;
}
signed main(){
    cin >> t;
    while (t--) solve();
    return 0;
}

总结

总而言之,这是一道非常优美的贪心题,它引导我们从模糊地如何决出胜负,一步一步深入思考 “怎么最大化赢面”“什么情况下不能操作”,体现了贪心思想的极致运用。

最后,祝各位 NOIP2025 RP++ ,贪心一眼看出正解,代码一遍就过!!!