把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ1141】[POI2009] Slw(神奇的斐波那契题目)

点此看题面

大致题意: 对于一个\(01\)\(x\),定义\(H(x)\)为将\(x\)\(1\)替换为\(10\)\(0\)替换为\(1\)的结果,\(H^m(x)\)则相当于对\(x\)\(m\)\(H\)操作后的最终串。现给定\(n\)以及\(a_1,a_2,..,a_n\),询问\(H^{a_1}(0)H^{a_2}(0)...H^{a_n}(0)\)是否是某个\(H^m(0)\)的子串(\(m\)为任意自然数)。

前言

满脑子只有大模拟的我,在推出性质之后就一直在思考怎么合并。。。

虽然和过去相比这次有些长进,一看模拟合并这么不可做,我也想过能不能用其他方法。结果想了半天也想不出还能怎么做,最后还是默默推合并至死。。。

最后点开题解发现少推了一个性质,真的是菜。

性质\(1\):斐波那契

从这个东西是怎么联想到斐波那契的呢?

我反正一看到\(1\)变成\(10\)\(0\)变成\(1\),就自然而然想到兔子繁殖,可以把\(0\)看成小兔子,\(1\)看成大兔子。

于是我们就发现:\(H^i(x)=H^{i-1}(x)+H^{i-2}(x)(i\ge 2)\)

性质\(2\):开头与结尾

开头:对于\(H^i(x)\),当\(i\)\(0\)时,开头是\(0\);当\(i\)\(1\)时,开头是\(1\)。根据斐波那契,每一个\(H^i(x)(i\ge 2)\)的开头都是\(H^{i-1}(x)\),因此除\(i=0\)以外所有\(H^i(x)\)开头必然是\(1\)

结尾:根据斐波那契,我们会发现\(H^i(x)\)的后半部分是\(H^{i-2}(x)\),也就是奇偶性相同的结尾相同。因此当\(i\)为偶数时\(H^i(x)\)结尾是\(0\)\(i\)为奇数时\(H^i(x)\)结尾是\(1\)

性质\(3\):逆操作

这是一个很关键的结论,就是因为没想到它,只推出前两个性质的我依旧啥也做不出来。

若我们定义\(x'=H^{-1}(x)\)表示\(x=H(x')\)(即\(H^{-1}(x)\)\(H(x)\)的逆操作),然后就会发现,若\(x\)是某一\(01\)\(y\)的子串,而根据先前斐波那契的性质\(x'\)必然是\(x\)的子串,也就是\(x'\)也是\(y\)的子串。

实际上,我们不光可以从\(x\)\(y\)的子串推出\(x'\)\(y\)的子串,还可以从\(x'\)\(y\)的子串推出\(x\)\(y\)的子串(因为此处\(H^m(x)\)我们完全可以视作\(H^{\infty}(x)\)),只不过在此题中这没啥用罢了。

不合法情况

现在,让我们来看看哪些情况是不合法的。

  1. 有连续两个\(0\)(良心的样例已经给了我们提示)。
  2. 考虑我们从已知不合法的两个\(0\)可以变换得到两个\(1\),但这貌似是合法的因为由\(01\)变换得到的\(110\)同样包含两个\(1\)。可如果是连续三个\(1\)呢?然后我们就发现这肯定是不合法的了。
  3. 再考虑我们从已知不合法的三个\(1\)可以变换得到\(101010\),这肯定也是不合法的。
  4. 。。。似乎根据我们的套路还可以继续从已知不合法的串往下推,但实际上已经没必要了。

如何判断

好了,综上所述讲了这么一大堆东西,那么我们究竟该怎么判断呢?

考虑性质\(3\),我们可以在全部\(a_i\)都大于\(0\)时给它们全部减\(1\),直至减出\(0\)为止。

然后我们要干什么呢?

对于每一个\(0\)我们讨论它前面的数是什么,然后发现:

  • 如果前面是偶数,由于偶数结尾是\(0\),有连续两个\(0\),所以不合法。
  • 如果前面是奇数,进一步分类讨论:
    • 如果前面是\(1\)\(H^1(0)=1\)),那我们可以把\(1\)\(0\)合并为\(2\)
    • 如果前面是\(3\)\(H^3(0)=101\)),那我们可以把它们合并为两个\(2\)
    • 否则,由于\(H^5(0)=10101\),根据奇偶性相同的串结尾相同的结论,对于所有\(i\ge 5\)\(i\)是奇数的情况,\(H^i(0)\)的结尾都是\(10101\),接上当前的\(0\)就是\(101010\),是上面的第三种不合法情况。

简单的说,对于\(1\)我们得到一个\(2\),对于\(3\)我们得到两个\(2\),其他情况都不合法。

最终如果能变成只剩一个数,那么就合法了。

开头与结尾的特殊操作

由于题目中要求的是子串,所以我们发现开头和结尾部分应该是可以向外扩展的,因此我们还需要进行如下几个操作:

  • 若开头是\(0\),此时由于前面没有数无法和上面一样分类讨论,考虑合法情况下向前扩展时\(0\)前面必然是\(1\)(因为两个\(0\)是非法的),所以我们可以把\(0\)修改为\(2\)
  • 若结尾是\(1\),显然它既可能是由\(0\)变来的,也可能是由\(1\)变来的\(10\)的前半部分,因此把它去掉完全不影响答案。如果结尾是\(11\),且不去掉这个\(1\),那么逆操作得到\(00\)就会判为非法。又如果结尾是\(111\),我们发现之前推不合法情况时之所以是三个\(1\),正是为了防止第二个\(1\)后面是\(0\),而我们去掉这第三个\(1\)后逆操作得到\(00\)正符合了我们的本意,那么此时第三个\(1\)也就没用了,完全可以去掉。
  • 若结尾是\(3\)\(H^3(0)=101\)),根据和上面相似的原因,我们可以去掉一个\(1\)得到\(2\)\(H^2(0)=10\)),这里就不再赘述了。

这样一来,这道题就真正做完了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
using namespace std;
int n,a[N+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define D isdigit(c=tc())
		char c,*A,*B,FI[FS];
	public:
		I FastIO() {A=B=FI;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
}F;
I bool Check()//验证
{
	RI i,n_;W(n^1)
	{
		!a[1]&&(a[1]=2),a[n]==1&&--n,a[n]==3&&(a[n]=2);//特殊操作开头结尾
		for(i=1;i<=n;++i) if(!a[i])//对于0
			{if(a[i-1]==1) a[i-1]=2,a[i]=-1;else if(a[i-1]==3) a[i-1]=a[i]=2;else return 0;}//-1表示删除
		for(n_=n,n=0,i=1;i<=n_;++i) ~a[i]&&(a[++n]=a[i]-1);//如果不是-1就统计下来
	}return 1;
}
int main()
{
	RI Tt,i;F.read(Tt);W(Tt--) {for(F.read(n),i=1;i<=n;++i) F.read(a[i]);puts(Check()?"TAK":"NIE");}
	return 0;
}
posted @ 2020-05-22 07:48  TheLostWeak  阅读(133)  评论(0编辑  收藏  举报