「解题报告」[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)

灾后重建「解题报告」

解题报告:hdu 1005 number subsequent

实验报告:统计字符串中子字符串出现的次数

有关α 、 β 、γ源的知识,还有在核子仪方面的相关使用原理,还请再详细说一下,谢谢