刚入深圳就一身病,太惨了. 赛时我跟个傻逼一样在一旁坐着看队友写题. 不出意外打铁了. 回老巢后身体好一些了, 脑袋也能用了, 于是乎我开始补题.
这道题目主要还是细节处理比较麻烦, 难度还算是简单. 农民胜利只有两种条件, 其一是 A 先把牌出完; 其二是 B 先把牌出完. 而前者还能再分两种情况, 即 A 可以自己独立把牌全出完和 A 需要在 B 的掩护下把牌出完.
我们不妨把比地主唯一一张小的牌称为小牌, 记作 small; 比地主大的牌记作大牌, 记作 big; 对子记作 num.
最简单的情况: A 可以自己独立把牌全出完.
什么时候 A 能独立出完呢? 只有 small1.size()<=1 时才可以. 此时 A 的策略就是先把大牌和对子出完, B 啥都不管 . 小牌没有直接赢, 小牌有一张出了 A 没牌农民直接获胜. 但显然我们聪明的 deepseek 并不知道这个规矩, 在我向它求助时一直在挑我这个毛病.
if(small1.size()<=1)YES;
第二简单? 的情况, B 可以独立把牌全部出完.
首先 B 的小牌最多只能有一张. 如果 B 的小牌超过一张, 倘若 B 能一直维持自己的牌权, 即一直能保证自己能一直成为先手. 在把所有的大牌和对子出完后自己出任意小牌, 地主都能跑掉. 如果此时只剩一张或没有小牌, 则 B 可以在地主打完所有牌之前自己先打完所有牌.
其次 A 能平稳把牌权交给 B.
- 经过我们第一轮的筛选后 A 肯定有小牌, 并且数量至少为 222, 所以当 B 有大牌的时候 B 一定能跑掉.
- 如果 B 无大牌, 则只要 AB 两者都有对子且 B 最大的对子比 A 最小的对子大即可, 这样也能平稳交牌权.
就这样完了吗?
有没有可能, B 不需要拿牌权也能赢?
当 B 没有对子, 没有大牌的时候, 也就是 B 的小牌有且仅有 111 张时, 只要 A 打出的小牌比 B 唯一的小牌小, B 可以直接把自己唯一的牌打出, 然后农民直接获胜.
我在补题时一直 WA 就是因为这个坑. 据队友说那天他们一直调试这道题也是因为这个锅. 同样这个锅 AI 也没有人能发现.
if(small2.size()==1){
if(big2.size())YES;
if(num2.size()&&num1.size()&&num2.back()>num1.front())YES;
if(num2.empty()&&small2.front()>small1.front())YES;
}
if(small2.empty()){
if(big2.size())YES;
if(num2.size()&&num1.size()&&num2.back()>num1.front())YES;
}
最后一种情况: A 在 B 的掩护下打出所有牌.
显然都知道 A 是要先出小牌然后 B 跟着出大牌, 所以 A 的小牌数不能比 B 的大牌数多 111 以上 ( 不包括 111), 否则 A 的小牌永远出不完.
其次, 当 B 拿到牌权时必须把牌权交给 A. 而交出牌权只有 A 出的牌压 B 一头才行. 所以我们要统计 A 大牌压 B 大牌的对数以及 A 对子压 B 对子的对数.
但同样, 如果要用对子交牌权的前提是 B 有大牌, 所以要在 B 剩余的大牌数和 A 对子压 B 对子对数之间取 min\minmin.
只要保证 A 的小牌数不比那两者之和多 111 以上 ( 不包括 111) 即可.
不包括 111 也很简单, 原理跟 A 独立出完一样. 我们聪明的 AI 一直在怀疑这种做法的正确性.
int can_use(0),can_use_pair(0);
for(int i1=(int)big1.size()-1,i2=(int)big2.size()-1;i1>=0&&i2>=0;--i2){
if(big1[i1]>big2[i2])P(can_use),--i1;
}
for(int i1=(int)num1.size()-1,i2=(int)num2.size()-1;i1>=0&&i2>=0;--i2){
if(num1[i1]>num2[i2])P(can_use_pair),--i1;
}
if((int)small1.size()-(int)big2.size()>1)NO;
int rb2s=big2.size()-can_use;
int add=std::min(rb2s,can_use_pair);
if((int)small1.size()-(add+can_use)>1)NO;
YES;
最后展示代码
#include<iostream>
#include<vector>
#define P(A) A=-~A
#define YES return std::cout<<"Yes\n",void(0)
#define NO return std::cout<<"No\n",void(0)
typedef long long LL;
int pc,n;
inline void solve(){
std::string s1,s2;
std::cin>>n>>s1>>s2>>pc;
std::vector<int>num1,num2,big1,big2,small1,small2;
for(int i=1;i<pc;P(i)){
if(s1[i-1]=='1')small1.push_back(i);
else if(s1[i-1]=='2')num1.push_back(i);
if(s2[i-1]=='1')small2.push_back(i);
else if(s2[i-1]=='2')num2.push_back(i);
}
for(unsigned int i=pc;i<=s1.size();P(i)){
if(s1[i-1]=='1')big1.push_back(i);
else if(s1[i-1]=='2')num1.push_back(i);
if(s2[i-1]=='1')big2.push_back(i);
else if(s2[i-1]=='2')num2.push_back(i);
}
if(small1.size()<=1)YES;
if(small2.size()==1){
if(big2.size())YES;
if(num2.size()&&num1.size()&&num2.back()>num1.front())YES;
if(num2.empty()&&small2.front()>small1.front())YES;
}
if(small2.empty()){
if(big2.size())YES;
if(num2.size()&&num1.size()&&num2.back()>num1.front())YES;
}
int can_use(0),can_use_pair(0);
for(int i1=(int)big1.size()-1,i2=(int)big2.size()-1;i1>=0&&i2>=0;--i2){
if(big1[i1]>big2[i2])P(can_use),--i1;
}
for(int i1=(int)num1.size()-1,i2=(int)num2.size()-1;i1>=0&&i2>=0;--i2){
if(num1[i1]>num2[i2])P(can_use_pair),--i1;
}
if((int)small1.size()-(int)big2.size()>1)NO;
int rb2s=big2.size()-can_use;
int add=std::min(rb2s,can_use_pair);
if((int)small1.size()-(add+can_use)>1)NO;
YES;
}
signed main(){
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
std::cout.tie(nullptr);
int T;
std::cin>>T;
while(T--)solve();
return 0;
}

2046

被折叠的 条评论
为什么被折叠?



