题目
神题!!只有(POI)出得出来的神题!!
只能说好像懂了,不想听蒟蒻废话就右转(dalao)的博客
目前网上除官方外仅三篇题解,由于推论无法直观得出且有点复杂,难免不好理解,手玩数据最重要
做法
由于都是以(H^x(0))开始,一下简写成(H^x)
性质:
(~~~~~1.)斐波那契堆:(H^x=H^{x-1}+H^{x-2})((0longrightarrow 1longrightarrow 10longrightarrow 101longrightarrow 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 vin {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;
}