两个人打台球,初始状态为n个编号不同的球和一个母球(编号为0),每个球的分数即它的编号,每次操作时,当前的目标球为台面上球的最小值,操作犯规的话会给对手加上若干分,犯规的情况有:
1 母球没有打到任何球,对手+目标球的分数
2 母球没有落袋,但是母球第一次撞击没有撞到目标球,或者是第一次撞击同时撞击了1个以上的球,对手+第一次同时撞击到的球中编号最大的分数
3 母球落袋并且撞击到了至少一个球,对手+第一次同时撞击到的球中编号最大的分数
在没有犯规的情况下,若目标球落袋,则我方的分数加上本轮落袋的球的分数和,并且下一轮依然是我方操作。如果我方犯规,或者是有球落袋但是目标球没有落袋,则对方再加上落袋的球的分数和。所有操作结束后,求A:B的分数。
很考验细心的一道模拟,注意到,我方得分的情况只有首先只撞到了一个球,并且这个球是目标球,并且母球没有落袋,目标球落袋,这种情况下我方加分,并继续行动,否则一定是对方加分并且换手,其中对方加分的情况中有一点要考虑到,如果我方犯规了,对方会加上罚分,并且如果这次操作有球落袋了,对手会再加上落袋求的分数和。考虑到这些,写的时候细心点这题也就没什么大问题了...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; int pt[3]; int a[1010]; int b[1010]; int c[1010]; bool f[101000]; int n,m,k,x,y,z,p,q; int x1,x2,x3,y1,y2,y3; int main() { // freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { memset(f,false,sizeof f); memset(pt,0,sizeof pt); int tgt=20200; for (int i=1; i<=n; i++) scanf("%d",&a[i]); sort(a+1,a+1+n); tgt=a[1]; int tgtnum=1; int side=0; int ad=side; int sum; for (int i=1; i<=m; i++) { f[0]=false; scanf("%d",&p); int minn=0; int minb=0; for (int i=1; i<=p; i++) scanf("%d",&b[i]),minn=max(minn,b[i]); if (p==1 && b[1]==tgt) { scanf("%d",&q); sum=0; minb=0; for (int i=1; i<=q; i++) { scanf("%d",&c[i]),minb=max(minb,c[i]),sum+=c[i]; f[c[i]]=true; } if (f[0]) { pt[side^1]+=minn; pt[side^1]+=sum; side^=1; } else { if (f[tgt]) pt[side]+=sum; else pt[side^1]+=sum,side^=1; } } else { scanf("%d",&q); minb=0; sum=0; for (int i=1; i<=q; i++) scanf("%d",&c[i]),minb=max(minb,c[i]),sum+=c[i],f[c[i]]=true; if (p==0) pt[side^1]+=tgt; else if (!f[0]) pt[side^1]+=minn; if (f[0] && p>0) pt[side^1]+=minn; pt[side^1]+=sum; side^=1; } while(f[a[tgtnum]] && tgtnum<=n) tgtnum++; if (tgtnum>n) break; tgt=a[tgtnum]; } cout<<pt[0]<<" : "<<pt[1]<<endl; } return 0; }