2018ACM/ICPC南京站網路賽C-GDY (補題)(暴力模擬)
題意:十三種牌1、2、...、13,和撲克牌一樣,不過JQK換成了11、12、13,大小是一樣的,即3<4<5<...<13<1<2。已知n個人,m張牌,初始每個人從1到n按順序各抽五張牌,可能出現牌堆已抓完但是最後一個人手中不足五張的情況,然後遊戲開始。遊戲過程中,每名玩家輪流出一張牌,第一個出牌的玩家必須出自己手中最小的一張牌,最開始是1先出牌,如果前一名玩家出了某張牌,那麼後一名玩家只能出“恰好”比它大的一張牌,或者出一張2(如果前一名玩家出的不是2),如果後一名玩家無法做到則跳過,換更後一名玩家接牌...如果某名玩家出牌後沒有其他玩家能出牌,則從該玩家開始每名玩家從牌堆中抓一張牌(如果牌堆已抓完則忽略抓牌這一操作),然後再由該名玩家第一個出牌。當某個玩家的牌出光了且牌堆已抓完的時候該玩家為勝者,其餘玩家將手裡的所有牌的數值加起來作為輸掉的分數。資料保證初始抓牌後每個人手中的牌數不為0。
解法當然是直接暴力模擬,不過這種模擬題一般在細節上會容易踩坑。
我在這裡根據自己的經驗講一些坑點和細節:首先,每個人抓五張牌後雖然保證每個人手中都有牌,但最後一個人可能抓了不到五張牌就抓牌結束了,需要判是否break。
然後,每當有人出牌後都需要他判斷手中剩餘牌的數量和牌堆是否已抓完,如果剩餘數量為0且牌堆已抓完說明遊戲結束。
連續沒人出牌需要用一個變數記錄,如果連續n-1人沒有出牌,這一輪出牌結束,從出牌的那個人開始抓牌。
正如出牌過程中要判斷玩家是否已經出完了牌,抓牌過程中也需要判斷牌堆是否已經抓完。
為了方便,我直接把1和2對映為14、15了,因此最好計算分數的時候需要轉化為1和2。
最後是注意迴圈出牌和抓牌時別寫錯了,其實0到n-1的迴圈好寫很多QAQ,但是我習慣了寫1到n,常常不小心寫錯。
#include<bits/stdc++.h> using namespace std; #define ll long long #define For(i,a,b) for(int i=a;i<=b;i++) #define INF 0x3f3f3f3f const int N = 20010; int t,n,m,cnt; int num[205][20],pri[205],minnum; int a[N]; int main(){ scanf("%d",&t); For(cas,1,t){ scanf("%d %d",&n,&m); For(i,1,m) scanf("%d",&a[i]); cnt=1; memset(num,0,sizeof(num)); memset(pri,0,sizeof(pri)); For(i,1,n){ For(j,1,5){ if(cnt>m)break; num[i][(a[cnt]<3)?(a[cnt]+13):a[cnt]]++,cnt++; pri[i]++; } } minnum=pri[1]; For(i,2,n) if(pri[i]<minnum) minnum=pri[i]; int now=1,tmp,tt; while(minnum>0){ for(int j=3;j<=15;j++){ if(num[now][j]>0){ tmp=j;num[now][j]--;pri[now]--;break; } } if(pri[now]==0&&cnt>m){ break; } tt=0; for(int i=now%n+1;;i=i%n+1){ if(tmp==15) break; if(num[i][tmp+1]>0) num[i][tmp+1]--,tmp++,pri[i]--,now=i,tt=0; else if(tmp<15&&num[i][15]>0) num[i][15]--,pri[i]--,tmp=15,now=i,tt=0; else{ tt++; } if(tt==n-1) break; if(pri[i]==0&&cnt>m) break; } if(cnt<=m){ for(int i=now;;i=i%n+1){ num[i][(a[cnt]<3)?(a[cnt]+13):a[cnt]]++,cnt++;pri[i]++; if(cnt>m) break; if(i==((now-2)%n+n)%n+1) break; } } minnum=pri[1]; For(i,2,n) if(pri[i]<minnum) minnum=pri[i]; } printf("Case #%d:\n",cas); int ans; For(i,1,n){ if(pri[i]==0){ printf("Winner\n"); } else{ ans=0; For(j,3,15){ if(num[i][j]>0) ans+=(num[i][j]*(j<14?j:(j-13))); } printf("%d\n",ans); } } } return 0; }