[POI2009]Slw

题目

神题!!只有\(POI\)出得出来的神题!!

只能说好像懂了,不想听蒟蒻废话就右转\(dalao\)博客

目前网上除官方外仅三篇题解,由于推论无法直观得出且有点复杂,难免不好理解,手玩数据最重要

做法

由于都是以\(H^x(0)\)开始,一下简写成\(H^x\)
性质:
\(~~~~~1.\)斐波那契堆:\(H^x=H^{x-1}+H^{x-2}\)\(0\longrightarrow 1\longrightarrow 10\longrightarrow 101\longrightarrow 10110\)

\(~~~~~2.\)\(x\)为偶数时\(0\)结尾,为奇数时\(1\)结尾

\(~~~~~3.\)定义\(G^-1\)\(H^1\)的逆操作,则\(s_1\)\(s_2\)的子串时,逆操作也有此性质

\(~~~~~4.\)出现\(00\)一定不合法

\(~~~~~5.\)出现\(111\)时则一定不合法,把这个子串化成一般形式为\(10101+0\)

\(~~~~~6.\)\(x≥5\)\(x\)为奇数时有后缀\(10101\),也就是说\(x≥5\)\(x+1=0\)时一定不合法

神奇的推导:
\(~~~~~\)我们把所有的\(x\),写成序列\(\{a_1,a_2...a_{n-1},a_n\}\)的形式

\(~~~~~\)\(\forall v\in \{a_1,a_2...a_{n-1},a_n\}>0\)时我们可以集体减\(1\)

\(~~~~~\)所以考虑\(0\)的特殊情况:

\(~~~~~\)前面为偶数一定不合法(性质\(2\)),考虑奇数:\((1:10\),合并转换为\(2)\)\((3:1010\),转换为两个\(2)\)

\(~~~~~\)剩下的都不合法了

特殊情况:
\(~~~~~\)由于性质\(4\)三子串的出现我们不好判断,而且两个\(1\)转换后不合法但是实际是合法的

\(~~~~~\)\(11\)出现在中间后面只能接\(0\),这种情况会合并的,\(11+x\)按之前的方法会判非法

\(~~~~~\)仅考虑在后面的情况,我们是可以直接去掉最后的\(1\)的,而\(111\)这种非法情况去掉后依然会判非法不用管了

\(~~~~~\)相似的,末尾\(3\)也会出现这种特殊情况改为\(2\)

My complete code

代码\(copy\)来的

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n;
int a[M];
bool Solve(){
	int i;
	while(n>1){
		if(!a[1]) a[1]=2;
		if(a[n]==1) n--;
		else if(a[n]==3) a[n]=2;
		for(i=n;i;i--)
			if(!a[i]){
				if(a[i-1]==1)
					a[i-1]=2,a[i]=-1;
				else if(a[i-1]==3)
					a[i-1]=2,a[i]=2;
				else
					return false;
			}
		int temp=0;
		for(i=1;i<=n;i++)
			if(a[i]!=-1)
				a[++temp]=a[i];
		n=temp;
		for(i=1;i<=n;i++)
			a[i]--;
	}
	return true;
}
int main(){
	int T,i;
	for(cin>>T;T;T--){
		cin>>n;
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		puts(Solve()?"TAK":"NIE");
	}
	return 0;
}

posted @ 2019-03-07 20:23  y2823774827y  阅读(240)  评论(0编辑  收藏  举报