• 「解题报告」[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;
    	}
        }
    }
    
  • 相关阅读:
    希尔伯特空间
    Java基础之类型转换总结篇
    超实用在线编译网站,编辑器
    3269: 万水千山粽是情
    Problem A: 李白打酒
    2370: 圆周率
    C语言fmod()函数:对浮点数取模(求余)
    C语言exp()函数:e的次幂函数(以e为底的x次方值)
    2543: 数字整除
    2542: 弟弟的作业
  • 原文地址:https://www.cnblogs.com/BruceW/p/13149523.html
Copyright © 2020-2023  润新知