Topcoder SRM598-Div1-Lv2 FoxAndFencing

涉及知识点:贪心

题意

在一个数轴上,Ciel 的棋子在 \(x=0\) 处编号为 \(1\),Liss的棋子在 \(x=d\) 处编号为 \(2\),两个棋子的最大移动距离与攻击范围为 \(mov,rng\ (\leq10^9)\),任意一方进行一个操作后检查对方棋子是否在己方棋子攻击范围内,若是则己方获胜。给出初始情况,双方均采用最优策略的情况下,判断游戏结果(Ciel 赢,Liss 赢,平局)。

Tips:一次操作后只检查对方棋子是否在己方攻击范围,而不立即检查己方棋子是否在对方攻击范围,也就是说如果能保证一击必胜那么即使进入对方攻击范围也能赢。

思路

数据范围与题目性质均说明了这题是个大分讨。

先特判开局就结束的情况,并且以下的分类讨论皆自动排除了开局即结束的情况。

考虑到一个性质,一个棋子实际攻击半径为 \(mov+rng\),因为该棋子可以先移动,然后判对方是否在攻击范围,那么可以得到结论:如果 \(mov_1+rng_1>mov_2+rng_2\),那么 \(1\) 一定不会输(以下皆反之同理),原因是 \(2\) 在一击必杀前必须保持在 \(1\) 的实际攻击半径之外才安全,而 \(2\) 由于实际攻击范围小于 \(1\),永远无法一击必杀。

既然 \(2\) 一定不会赢,那么根据最优策略 \(2\) 一定是希望平局,那么 \(2\) 就会竭力逃跑,我们总结 \(1\) 能追上并击杀 \(2\) 的充要条件为:

  • \(mov_1>mov_2\)​,很明显,如果不满足该条件二者距离只会越拉越大。
  • \(rng_1\geq mov_2+rng_2+1\)\(mov_1+rng_1\geq mov_2+rng_2+mov_2+1\)\(1\) 在追杀 \(2\) 时在确保一击必杀时必须保持在 \(2\) 的实际攻击半径外避免被反杀,即和 \(2\) 保持至少 \(mov_2+rng_2+1\) 的距离,但如果 \(rng_1\geq mov_2+rng_2+1\),那么 \(1\) 就可以在 \(2\) 实际攻击半径外安全地击杀 \(2\),不然就给了 \(2\) 逃跑的机会,逃跑后 \(1\)\(2\) 的距离为 \(mov_2+rng_2+mov_2+1\),如果 \(1\) 的实际攻击半径大于等于该距离,\(1\) 就能追上并一击必杀,否则即使 \(1\) 跑步速度比 \(2\) 快,每次都会重复“追上-逃跑”这样的循环,游戏平局。另外注意到这两个条件后者其实就是前者的弱化版,所以实际编码时只用判断后者即可

因此我们也能推出,如果 \(mov_1+rng_1=mov_2+rng_2\),游戏一定平局。

代码

#include<bits/stdc++.h>
// #define puts(x); puts(x),cout<<__LINE__<<endl;
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar __getchar
inline char __getchar(){
    static char ch[1<<20],*l,*r;
    return (l==r&&(r=(l=ch)+fread(ch,1,1<<20,stdin),l==r))?EOF:*l++;
}
#endif
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
long long mov[3],rng[3],d;
int main(){
    rd(mov[1]);rd(mov[2]);rd(rng[1]);rd(rng[2]);rd(d);
    if(mov[1]+rng[1]>=d){
        puts("Ciel");
        return 0;
    }
    else if(mov[1]+d<=mov[2]+rng[2]){
        puts("Liss");
        return 0;
    }

    if(mov[1]+rng[1]==mov[2]+rng[2]){
        puts("Draw");
    }
    else if(mov[1]>mov[2] && mov[1]+rng[1]>mov[2]+rng[2]+mov[2]){
        puts("Ciel");
    }
    else if(mov[2]>mov[1] && mov[2]+rng[2]>mov[1]+rng[1]+mov[1]){
        puts("Liss");
    }
    else{
        puts("Draw");
    }
    return 0;
}
posted @ 2024-04-25 11:08  MessageBoxA  阅读(26)  评论(0编辑  收藏  举报