acm-(好题、贪心、思维)Codeforces Round #674 (Div. 3) E. Rock, Paper, Scissors

题面
传送门
首先是一波暴力打法,考虑直接枚举Alice的出拳顺序,并且保证当前拳头用完后再进入下一个拳头类型。对于当前拳头,枚举对局的Bob的拳头即可。

#include <bits/stdc++.h>
using namespace std;



const int inf = 2147483647;

int a[3],b[3],aa[3],bb[3],c[3];
int ans1=inf,ans2=0;
bool win(int a,int b){
    return a==0&&b==1 || a==1 &&b==2 || a==2 && b==0;
}
void dfs(int cur,int ans){
    if(cur==3){
        ans1=min(ans1,ans);
        ans2=max(ans2,ans);
        return;
    }
    for(int i=0;i<3;++i){
        if(!b[i])continue;
        if(win(c[cur],i)){
            int mi=min(a[c[cur]],b[i]);
            a[c[cur]]-=mi;
            b[i]-=mi;
            if(!a[c[cur]])dfs(cur+1,ans+mi);
            else dfs(cur,ans+mi);
        }else {
            int mi=min(a[c[cur]],b[i]);
            a[c[cur]]-=mi;
            b[i]-=mi;
            if(!a[c[cur]])dfs(cur+1,ans);
            else dfs(cur,ans);
        }
        a[c[cur]]=aa[c[cur]];
        b[i]=bb[i];
    }
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<3;++i)scanf("%d",&a[i]),aa[i]=a[i];for(int i=0;i<3;++i)scanf("%d",&b[i]),bb[i]=b[i];
    c[0]=0,c[1]=1,c[2]=2;
    do{
        dfs(0,0);
    }while(next_permutation(c,c+3));
    printf("%d %d\n",ans1,ans2);
}

当然暴力解法虽然无脑,但是写起来相对复杂, 这里给出一个更加简单的贪心做法。

首先考虑赢的最大次数,显然是 m i n ( a 1 , b 2 ) + m i n ( a 2 , b 3 ) + m i n ( a 3 , b 1 ) min(a_1,b_2)+min(a_2,b_3)+min(a_3,b_1) min(a1,b2)+min(a2,b3)+min(a3,b1)

对于赢的最小次数而言,考虑Alice是用石头、剪刀、布中的哪一种赢的Bob,事实上在最坏情况下不可能同时存在两个拳头赢得Bob,假设 a 1 − b 1 − b 3 > 0 a1-b1-b3>0 a1b1b3>0,也就是最坏情况下石头赢了Bob一部分,那么另一个拳头必定无法赢Bob,假设剪刀也赢了Bob,那么有 a 1 + a 2 − b 1 − b 2 − b 3 > 0 a1+a2-b1-b2-b3>0 a1+a2b1b2b3>0,这显然不符合题意,故只有一个拳头能够赢得Bob。
此外我们还能发现在任何初始条件下最多只有一个拳头能满足赢Bob的条件,假设石头和剪刀都具备赢Bob的条件,即满足 a 1 − b 1 − b 3 > 0 , a 2 − b 2 − b 1 > 0 a1-b1-b3>0,a2-b2-b1>0 a1b1b3>0,a2b2b1>0,那么有 a 1 + a 2 − 2 b 1 − b 2 − b 3 > 0 a1+a2-2b1-b2-b3>0 a1+a22b1b2b3>0,显然不符合题意,因此我们最多能够找到一个拳头赢Bob,并且当你能找到这个拳头符合赢Bob条件的时候,不管怎么分配,这个拳头必定会赢Bob,为了最小化这个拳头的胜率,我们让所有的它的克星与它对决即可,简单起见可以写成 m a x ( 0 , a 1 − b 1 − b 3 , a 2 − b 2 − b 1 , a 3 − b 3 − b 2 ) max(0,a1-b1-b3,a2-b2-b1,a3-b3-b2) max(0,a1b1b3,a2b2b1,a3b3b2)

#include <bits/stdc++.h>
using namespace std;



int main(){
    int a1,a2,a3,b1,b2,b3;
    int n;
    scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&a3,&b1,&b2,&b3);
    printf("%d %d\n",max(0,max(a1-b1-b3,max(a2-b2-b1,a3-b3-b2))),min(a1,b2)+min(a2,b3)+min(a3,b1));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值