ACM-ICPC 2018 南京赛区网络预赛_C_GDY_大模拟

传送门
题意:
1)有m张牌放到栈里
2)牌的大小为3<4<5<6<7<8<9<10<11<12<13<1<2
3)n个人,每个人首先每次从栈顶取5张牌。
4)从第1个人出他手里最小的牌,然后按顺序轮流出牌。
5)出牌有两种选择:①出比前一个人的牌大1的牌 ②出2
6)当一个人出了一张2以后,从他开始每个人抽一张牌。
7)如果第i个人没有能出的牌,他就pass。
8)如果第X个人出完牌后除了他之外没有人能出牌,那么从他开始所有人要抽一张牌,然后,X出他手里最小的牌。
9)如果栈里没牌了,那么就跳过取牌的环节
10)谁先出完牌谁胜,剩下的人输出他手中牌的点数和。
思路:模拟。

虽然比赛还是过了,但是还是有一些在模拟中的几个待改进的点:
1)可以建立一个虚拟的0,这样第一个不需要特别判断。
2)这样的顺序可以1,2 变成14,15,避免这之后的判断中出现错误和繁琐的if。
3)记录上一个出牌的人。
4)发牌的时候一张一张发,这张的话所有的发牌操作可以用一个函数来写。

#include<bits/stdc++.h>
#define debug(a) cout << #a << " " << a << endl
#define lnn putchar('\n')
#define see putchar(' ')
#define LL long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-6
const int N=2e5+7;
using namespace std;
int a[N];
int f[250][15];
int cnt,n,m;
void init()
{
    for(int i=1;i<250;i++)
        for(int j=0;j<15;j++) f[i][j]=0;
}
void add(int now)
{
    if(cnt>=m) return;
    for(int i=1;i<=n;i++){
        int nx=now+i-1;
        if(nx>n) nx-=n;
        f[nx][a[++cnt]]++;
        if(cnt==m) break;
    }
}
int check(int now)
{
    for(int i=1;i<=13;i++){
        if(f[now][i]) return 0;
    }
    return 1;
}
int main ()
{
    //yyy_3y
    //freopen("1.in","r",stdin);
    int T; scanf("%d",&T);
    for(int Case=1;Case<=T;Case++){
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d",&a[i]);
        cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=5;j++){
                f[i][a[++cnt]]++;
                if(cnt==m) break;
            }
            if(cnt==m) break;
        }

        int now_person=1;
        int pre_card;
        for(int i=2;i>=1;i--)   if(f[1][i]) pre_card=i;
        for(int i=13;i>=3;i--)  if(f[1][i]) pre_card=i;
        int flag=1;
        int ccc=0;
        if(pre_card==1) pre_card=13;
        else if(pre_card==3)  pre_card=-1;
        else pre_card--;
        while(flag){
            if(pre_card==-1){
                f[1][3]--;
                if(check(now_person)) break;
                now_person++;
                if(now_person>n) now_person-=n;
                pre_card=3;
                continue;
            }

            if(pre_card==2){
                add(now_person);
                int now_card=-1;
                for(int i=2;i>=1;i--)   if(f[now_person][i]) now_card=i;
                for(int i=13;i>=3;i--)  if(f[now_person][i]) now_card=i;
                f[now_person][now_card]--;
                if(check(now_person)) break;
                if(now_card!=2)   now_person++;
                if(now_person>n) now_person-=n;
                pre_card=now_card;
            }else{
                int now_card=pre_card+1;
                if(now_card==14) now_card=1;
                if(f[now_person][now_card] && now_card!=2){
                    f[now_person][now_card]--;
                    if(check(now_person)) break;
                    now_person++;
                    if(now_person>n) now_person-=n;
                    pre_card=now_card;
                    ccc=0;
                }else if(f[now_person][2]){
                    f[now_person][2]--;
                    if(check(now_person)) break;
                    pre_card=2;
                    ccc=0;
                }else{
                    ccc++;
                    now_person++;
                    if(now_person>n) now_person-=n;
                }
                if(ccc==n-1){
                    ccc=0;
                    add(now_person);
                    int now_card=-1;
                    for(int i=2;i>=1;i--)   if(f[now_person][i]) now_card=i;
                    for(int i=13;i>=3;i--)  if(f[now_person][i]) now_card=i;

                    f[now_person][now_card]--;
                    if(check(now_person)) break;
                    now_person++;
                    if(now_person>n) now_person-=n;
                    pre_card=now_card;
                }
            }

        }
        printf("Case #%d:\n",Case);
        for(int i=1;i<=n;i++){
            int ans=0;
            for(int j=1;j<=13;j++){
                ans+=f[i][j]*j;
            }
            if(!ans) puts("Winner");
            else printf("%d\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值