「解题报告」[luoguP6585]中子衰变 (交互题 分类讨论)
Posted brucew
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「解题报告」[luoguP6585]中子衰变 (交互题 分类讨论)相关的知识,希望对你有一定的参考价值。
「解题报告」[luoguP6585]中子衰变 (交互题 分类讨论)
题面
题意
有一个长度为 (n) ,初始为 (0) 的序列 (a).
每次操作可以将一个 (0) 变为 (1) 或 (-1), 并满足 (1) 和 (-1) 不相邻.
最后无法操作的一方为输家.
特殊地, 若最后整个序列全部变为 (1) 或 (-1), 则后手胜.
由玩家选择先手/后手, 每次输入一个二元组 ((p,ty)), 表示将 (a_p) 变为 (ty), 每次输出一个二元组 ((p,ty)), 表示将 (a_p) 变为 (ty).
制定策略, 确保我方能胜利.
数据范围
(1 le n le 2^10).
思路
主要思想 : 分奇偶讨论.
胜负情况
(n)为偶数
最终空格数量 | 奇数 | 偶数 | 0 |
---|---|---|---|
胜者 | 先手 | 后手 | 后手 |
左右端点粒子 | 不同 | 相同 | 相同 |
n为奇数
最终空格数量 | 奇数 | 偶数 | 0 |
---|---|---|---|
胜者 | 后手 | 先手 | 后手 |
左右端点粒子 | 不同 | 相同 | 相同 |
由上表可知, 我们可以通过控制左右端点粒子是否相同来控制胜负情况.
为了控制左右端点是否相同, 我们需要让对手先改变其中一个端点上的粒子, 再在另一个端点填上对应的粒子.
这样我们可以先排除左右两端点, 然后进行一个类似递归的子任务. (当然实现过程不是递归.)
具体的实现过程需要分奇偶讨论, 然后制定策略, 使得在每个阶段, 都让对手先改变端点上的粒子, 或者保持所有粒子一致.
具体策略
(n) 为偶数
若选择先手, 则后手每次都可以在序列的轴对称位置填上一个相同的数, 使左右端点粒子相同, 这样必输.
所以我们选择后手, 每次在序列的轴对称位置填上与对手相同的数, 这样左右端点粒子就一定是相同的.
(n) 为奇数
若选择先手, 若第一步不选择中点, 则会落得与 (n) 为偶数时一样的下场; 若第一步选择中点, 对手可以紧贴这我们选择的点来填相同的点, 如果一直填下去, 对手就赢了, 所以我们被迫要在端点填上一个与原来不同的点, 这时对手又可以在对应位置填上一个和我们不同的点, 还是对手赢.
所以我们还是选择后手, 维护一个被改变了的区间 ([l,r]), 且 (l,r) 轴对称, 每次在区间里填点或者紧贴着区间边界填点. 若对手在端点上填了一个与原来不同的点, 我们就在轴对称位置填上一个与它不同 (与原来相同) 的点.
代码
#include<bits/stdc++.h>
using namespace std;
const int _=2e3+7;
int n,a[_],rev[_],tag,p,ty,lc,rc;
bool fl;
bool judge(int i){
if(a[i]!=0) return 0;
if(a[i+1]==1&&a[i-1]==-1) return 0;
if(a[i+1]==-1&&a[i-1]==1) return 0;
return 1;
}
bool check(){
for(int i=1;i<=n;i++)
if(judge(i)) return 1;
return 0;
}
bool find(){
for(int i=lc;i<=rc;i++)
if(judge(i)){
if(a[i-1]!=0) a[i]=a[i-1];
else if(a[i+1]!=0) a[i]=a[i+1];
else a[i]=tag;
cout<<i<<‘ ‘<<a[i]<<endl;
return 1;
}
return 0;
}
int main(){
#ifndef ONLINE_JUDGE
//freopen("x.in","r",stdin);
#endif
memset(a,0,sizeof(a));
cin>>n>>ty;
cout<<1<<endl;
for(int i=1;i<=n;i++) rev[i]=n-i+1;
if(n==1){
cin>>p>>ty;
return 0;
}
else if(n==2){
cin>>p>>ty;
if(p==1) cout<<2<<‘ ‘<<ty<<endl;
else cout<<1<<‘ ‘<<ty<<endl;
return 0;
}
else if(n==3){
cin>>p>>ty;
if(p==1) cout<<2<<‘ ‘<<ty<<endl;
else cout<<1<<‘ ‘<<ty<<endl;
cin>>p>>ty;
return 0;
}
else if(!(n%2)){
while(1){
cin>>p>>ty;
a[p]=ty;
a[rev[p]]=ty;
cout<<rev[p]<<‘ ‘<<ty<<endl;
if(!check()) return 0; // 若游戏结束, 需立刻结束程序(题目要求)
}
}
else{
lc=n/2; rc=n/2+2;
cin>>p>>ty; tag=ty;
if(rev[p]==p){
a[p]=ty; a[lc]=ty;
cout<<lc<<‘ ‘<<ty<<endl;
if(lc>1){ lc--; rc++; }
while(1){
cin>>p>>ty;
a[p]=ty;
if(p>=lc&&p<=rc){
find();
if(a[lc]!=0||a[rc]!=0){
if(lc>1){ lc--; rc++; }
}
}
else{
a[rev[p]]=-ty;
cout<<rev[p]<<‘ ‘<<-ty<<endl;
lc=min(p,rev[p]);
rc=max(p,rev[p]);
cin>>p>>ty;
break;
}
if(!check()) return 0;
}
}
while(1){
a[p]=ty;
if(p>=lc&&p<=rc) find();
else{
a[rev[p]]=-ty;
cout<<rev[p]<<‘ ‘<<-ty<<endl;
lc=min(p,rev[p]);
rc=max(p,rev[p]);
}
if(!check()) return 0;
cin>>p>>ty;
}
}
}
以上是关于「解题报告」[luoguP6585]中子衰变 (交互题 分类讨论)的主要内容,如果未能解决你的问题,请参考以下文章
「解题报告」[luoguP6584]重拳出击 (贪心).md
「解题报告」[luoguP6594]换寝室 (二分答案 树形DP)