BZOJ1141: [POI2009]Slw

来源:互联网 发布:编译安卓rr源码教程 编辑:程序博客网 时间:2024/06/07 22:43

好神呀…

手玩一下发现这个H(s)生成的串有个斐波那契的递推式
emmmmm然后我就啥都不会了….

我们定义G(s)为H(s)的逆变换,即H(a)=b,G(b)=a
那么对于s中的每个1,如果后面是0,他会变成1,否则变成0
发现我们要验证s是否是S的子串,这个问题等价于验证G(s)是否是G(S)的子串
我们可以不断对s做逆变换,让他越来越短

我们先来证几个结论
1:Hn的偶数项最后一位是0,奇数项最后一位是1
2:Hn(n>0)第一位为1
3:Hn中不存在00
4:Hn(nn>=5)最后有一段10101
5:Hn(nn>=5)后面不能接0 (由性质4,若接0,101010,对Hn逆变换2次后会有00项,一定不是S的子串(由性质2))

用发现的那个斐波那契性质易证

然后考虑对s做逆变换

s由很多个Hai拼在一起,当ai都>0时,Hai(i<n)后面都跟着一个1(结论2),所以不用考虑后面的东西对Hai逆变换的影响,G(Hai)=Hai1直接ai-=1

对于H_{an}Han
若an为偶数,s最后一位时0,s后面的东西不会影响G(s),直接an–,
若an为奇数,当an=1时,因为s后面可以跟1或0,发现此时an不影响整个s是否是S的子串,直接将an删去;an=3时,同样可以删去最后一个1,让an=2,an-=1变成1;an>=5时,因为后面不能接0,可以直接an-=1

一直这样缩直到出现ai=0,这时不能再分别缩了因为没有G(H0)这个东西,要将他和前面合并
对于一个位置ai=0
ai1是偶数,出现00不合法
ai1是奇数
1:ai1=1,合并在一起,ai1=2
2:ai1=3,变成1010,ai1=ai=2
3:ai1>=5,出现101010,不合法

因为ni=1ai<=1e7 操作直接暴力过整个序列就行了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void read(int &x){    char c; while(!((c=getchar())>='0'&&c<='9'));    x=c-'0';    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';}const int maxn = 1100000;int n,m;int a[maxn];int main(){    int tcase; read(tcase);    while(tcase--)    {        read(n);        for(int i=1;i<=n;i++) read(a[i]);        bool flag=true;        while(n>1&&flag)        {            if(a[n]==1) n--;            else if(a[n]==3) a[n]=2;            for(int i=1;i<=n;i++) if(!a[i])            {                if(i==1) a[i]=2;                else                {                    int j=i-1; if(!a[j]) j--;                    if(a[j]&1)                    {                        if(a[j]>=5) { flag=false; break; }                        else if(a[j]==1) a[j]=2;                        else a[j]=a[i]=2;                    }                    else { flag=false; break; }                }            }            m=0; for(int i=1;i<=n;i++) if(a[i]) a[++m]=a[i]-1;            n=m;        }        puts(flag?"TAK":"NIE");    }    return 0;}
原创粉丝点击