• bzoj2066: [Poi2004]Gra


    传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2066

    思路:首先谁移到m-1谁就输了,这是多么显然啊....

    其实这个可以转化为上一篇中的阶梯NIM。

    连续的一堆就是一个阶梯上的石子,两个连续的一堆间隔的空阶梯数是空格数-1(这点一定要注意)

    然后考虑对于连续的一堆棋子,如果我们从中间移走一个,使之变为数量为x和y的两段,那么就等价于从一个阶梯向下一个阶梯移动了y个石子。


    对于方案数,只要枚举+判断就可以了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=1000010;
    using namespace std;
    int n,m,a[maxn],cnt,b[maxn],ans,tot;char ch;
    
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    
    int main(){
    	scanf("%d%d",&m,&n);
    	for (int i=1;i<=n;i++) read(a[i]);
    	if (a[n]==m-1){
    		ans=1;
    		for (int i=n;i&&a[i]-a[i-1]==1;i--,ans++);
    		return printf("%d
    ",ans),0;
    	}
    	a[n+1]=m-1;
    	for (int i=n;i;i--)
    		if (a[i+1]-a[i]==1) b[cnt]++;
    		else if (a[i+1]-a[i]==2){
    			if (cnt&1) ans=ans^b[cnt];
    			b[++cnt]=1;
    		}
    		else{
    			if (cnt&1) ans=ans^b[cnt];
    			cnt+=3-((a[i+1]-a[i])&1),b[cnt]=1;
    		}
    	if (cnt&1) ans=ans^b[cnt];
    	if (ans)
    		for (int i=1;i<=cnt;i++)
    			if ((i&1)&&(ans^b[i])<b[i]||i%2==0&&(ans^b[i-1])>b[i-1]&&(ans^b[i-1])<=b[i-1]+b[i])
    				tot++;
    	printf("%d
    ",tot);
    	return 0;
    }
    


  • 相关阅读:
    加一
    斐波那契数
    整数的各位积和之差
    移除元素
    删除排序数组中的重复项
    有效的括号
    爬楼梯
    最长公共前缀
    罗马数字转整数
    回文数
  • 原文地址:https://www.cnblogs.com/thythy/p/5493552.html
Copyright © 2020-2023  润新知