题解:P12400 [COI 2025] 人工智能 / Automatizacija(暂时无法评测)
DanielDingDang · · 题解
终于弄懂了,太妙了!
千万不要想歪了,考虑直接让先手完整告诉后手自己的集合。对于一个数
但是一个问题:由于每次双方都必须选择一个格子进行染色,当后手选择的位置恰好与先手的某个位置重复时就麻烦了。举个例子,
现在,我们希望后手进行的这些无意义的操作都不要干扰到先手的操作,也就是后手选择的格子都和先手选择的格子不同。这看上去几乎不可能做到。很显然,如果先手按照任意顺序染色的话,肯定是无法完成任务的,因为这样以来后手只能瞎猜凭运气。
为了让这一点可能做到,首先一个必要条件就是
很好,接下来我们只需处理
我们先想想,最直观、简单的方法是什么?先手从小到大传自己的数,后手填充最左侧的空的位置,如此进行。但是这显然会出现问题。比如,先手的集合是
先手从小到大传自己的数也太傻了!实际上,我们可以把先手集合中的数排成一个环形。比如说,
- 先手传
3 ,后手传最左侧的空位4 。 - 先手传
5 ,后手传6 。 - 先手传
1 ,后手传7 。 - 先手传
2 ,后手传8 。
完美完成了任务!
可惜的是,我们还需要解决以下两个问题:
- 在
k 种传输顺序中,一定存在一种使得可以满足我们的需求吗? - 后手怎么知道下一个空位是啥?我们只能知道当前的状态啊,更不可能知道先手选的起点是啥。
第二个问题是很容易解决的。双方填数的编号一定是从
关键是第一个问题,在
如果一个起点是合法的,开头是
我们举个例子吧!比如
我们解释一下。如果灰色的位置个数
我们就可以把他视为一条路径,
开头相当于是
一个经典操作是,我们将坐标系转化为:
我们考虑以
所以,起点就被定下来了,整个问题也得到了完美的解决。
给出我的代码,是目前 QOJ 最短解(再过几天就肯定要被超越了)。注意:这份代码是 QOJ 上的输入/输出格式,和洛谷上的输入/输出格式有所不同,思路完全遵循上述题解。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define F(i, a, b) for (int i = (a); i <= (b); i ++ )
#define DF(i, a, b) for (int i = (a); i >= (b); i -- )
const int N=100;
int op,n,k,a[N],st[N],v[N],pre[N],sz,f=0;
char ch[N];
void pt(int x){
if(ch[x]=='.')cout<<"+ "<<x<<endl;
else F(i,1,n)if(ch[i]=='.')return cout<<"+ "<<i<<endl,void();
}
void solve(){
F(i,1,n)cin>>ch[i];
int cc=0;F(i,1,n)cc+=ch[i]!='.';if(cc==n)return cout<<"! "<<n<<endl,void();
int cnt=0;F(i,1,n)cnt+=ch[i]=='P';
if(op==2&&k==n||op==1&&cnt>=sz)return cout<<"! "<<n<<endl,void();
if(op==2&&(cnt==k||cnt==n-k)){
int res=0;
if(f){F(i,1,n)if(ch[i]!='P')res+=st[i];}
else{F(i,1,n)if(ch[i]=='P'){res+=st[i];}}
cout<<"! "<<res<<endl;return;
}
if(op==1)return pt(v[cnt+1]);
int blk=0;F(i,1,n)if(ch[i]=='.')blk=i;
int fl=0;F(i,blk+1,n)if(ch[i]=='C')fl=1;
if(cnt==1)F(i,1,n)if(ch[i]=='P')return pt(i+1);
if(!fl){
int pos=0;F(i,1,n)if(ch[i]=='C')pos=i;
int pos2=0;F(i,pos,n)if(ch[i]=='.')return pt(i);
cout<<"+ "<<pos2<<endl;
}else pt(0);
}
signed main()
{
cin>>op>>n>>k;F(i,1,k)cin>>a[i];
f=k>n/2;
if(op==1&&k>n/2){
F(i,1,k)st[a[i]]=1;int cc=0;
F(i,1,n)if(!st[i])a[++cc]=i;k=cc;
memset(st,0,sizeof st);
}
F(i,1,k)st[a[i]]=1;sort(a+1,a+k+1);
F(i,1,n)pre[i]=pre[i-1]+(st[i]?-1:1);
int res=1e18,p=0;F(i,1,n)if(st[i]&&pre[i]<res)res=pre[i],p=i;
F(i,1,k)if(a[i]>=p)v[++sz]=a[i];
F(i,1,k)if(a[i]<p)v[++sz]=a[i];
int T;cin>>T;while(T--)solve();
return 0;
}
有问题可以评论或私信哦!