题解:P7506 「Wdsr-2.5」琪露诺的算数游戏

· · 题解

思路

大模拟,打法暴力。单独考虑普通牌和解牌。

对于普通牌,因为只有三张手牌,所以我们可以在每次 选择出牌时都遍历一遍,找到最大或最小的合法牌。

对于解牌,只有三种,可以暴力搞。按优先级遍历三遍,分别找是否有对应的牌,如果有直接出就好。

比较难处理的是 DOUBLE 标记,其实标记只会传给下一个人,我们只要记录标记是否传递着。如果用解牌跳过,那么标记仍在传递。如果没有解牌只能用普通牌,这时无论输赢,标记都会被消除。

注意事项

  1. 出牌的优先级在有 DOUBLE 标记和没有时不一样, 没有标记时为乘法牌、加法牌、减法牌、除法牌、固定牌,尽可能大,有标记时为除法牌、减法牌、加法牌、乘法牌、固定牌,尽可能小,我们可以预处理优先级。

  2. 如果有标记时要优先出解牌,没有标记优先出普通牌。DOUBLE 标记如果用解牌消掉直接跳下一个人,否则还要按没有标记的再出一次牌。

  3. 出牌顺序每次重置。

  4. 如果输了要重新摸三张牌。

  5. 负数向下取整的问题,在这道题中因为只有除二的操作,所以我们可以直接用右移一代替。

  6. 建议多写函数,把各个函数调好了再整合。

参考代码

注释很详细。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
int n,m,k,now,st,p,fl=1;
string d[N];
bool dou;
map<char,int> mp[2]={{{'C',1},{'A',2},{'B',3},{'D',4},{'E',5}},{{'D',1},{'B',2},{'A',3},{'C',4},{'E',5}}};
//注意优先级 
struct P
{
    string name;
    string c[3];
} a[35];
int cal(int x,string c)
{
    int len=c.length(),tmp=0;
    if(len==2) tmp=c[1]-48;
    else tmp=(c[1]-48)*10+c[2]-48;
    if(c[0]=='A') return x+tmp;
    else if(c[0]=='B') return x-tmp;
    else if(c[0]=='C') return x*2;
    else if(c[0]=='D'&&c[1]!='O') return x>>=1;//和 DOUBLE 区分,注意向下取整 
    else if(c[0]=='E') return tmp; 
    else return 10000000;// 单独考虑解牌,这里不计 
}
bool jd(int i)//暴力搞 
{
    for(int j=0;j<3;j++) if(a[i].c[j]=="PASS")
    {
        cout<<a[i].name<<" used "<<a[i].c[j]<<",now p="<<p<<".\n";
        a[i].c[j]=d[++now]; return 1;   
    }
    for(int j=0;j<3;j++) if(a[i].c[j]=="TURN")
    {
        cout<<a[i].name<<" used "<<a[i].c[j]<<",now p="<<p<<".\n";
        a[i].c[j]=d[++now];fl*=-1; return 1;            
    }   
    for(int j=0;j<3;j++) if(a[i].c[j]=="DOUBLE")
    {
        cout<<a[i].name<<" used "<<a[i].c[j]<<",now p="<<p<<".\n";
        a[i].c[j]=d[++now]; dou=1; return 1;
    }
    return 0;
}
pair<int,int> work(int i,bool op)
{
    int tm,id;
    if(op==0)
    {
        tm=-1e9,id=-1;
        for(int j=0;j<3;j++)
        {
            int tmp=cal(p,a[i].c[j]);
            if(tmp>99) continue;
            else if(tmp>tm) tm=tmp,id=j;//较大的 
            else if(tmp==tm)
            {
                if(mp[op][a[i].c[id][0]]>mp[op][a[i].c[j][0]]) id=j;
            }
        }       
    }
    else
    {
        tm=1e9,id=-1;
        for(int j=0;j<3;j++)
        {
            int tmp=cal(p,a[i].c[j]);
            if(tmp>99) continue;
            else if(tmp<tm) tm=tmp,id=j;//较小的 
            else if(tmp==tm)
            {
                if(mp[op][a[i].c[id][0]]>mp[op][a[i].c[j][0]]) id=j; 
            }
        }       
    }
    return make_pair(tm,id);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].name>>a[i].c[0]>>a[i].c[1]>>a[i].c[2];
    }
    for(int i=1;i<=k;i++) cin>>d[i];
    st=1;
    for(int g=1;g<=m;g++)
    {
        printf("Round %d:\n",g);
        p=0; fl=1;//重置 
        for(int i=st;;i+=fl)
        {
            if(i==n+1) i=1;
            if(i==0) i=n;
            if(dou)
            {
                if(!jd(i))//先判解牌 
                {
                    dou=0;//没有解牌,消除标记 
                    pair<int,int> pii=work(i,1);
                    int id=pii.second,tm=pii.first;
                    if(id!=-1) 
                    {
                        p=tm;
                        cout<<a[i].name<<" used "<<a[i].c[id]<<",now p="<<p<<".\n";
                        a[i].c[id]=d[++now];
                    }
                    else 
                    {
                        if(jd(i)) continue;
                        cout<<a[i].name<<" lost the game.\n";
                        for(int j=0;j<3;j++) a[i].c[j]=d[++now];
                        st=i; break;
                    }                                   
                }
                else continue;//注意直接跳 
            }
            pair<int,int> pii=work(i,0);
            int id=pii.second,tm=pii.first;
            if(id!=-1) 
            {
                p=tm; 
                cout<<a[i].name<<" used "<<a[i].c[id]<<",now p="<<p<<".\n";
                a[i].c[id]=d[++now];
            }
            else 
            {
                if(jd(i)) continue;//判解牌 
                cout<<a[i].name<<" lost the game.\n";
                for(int j=0;j<3;j++) a[i].c[j]=d[++now];
                st=i; break;
            }
        }
    }
    return 0;
}