zoukankan      html  css  js  c++  java
  • CodeForces 526D

    呵呵,先贴一张图:(这就是我CodeForces的头像(至少现在是))

    洛谷题目页面传送门 & CodeForces题目页面传送门

    给定字符串(a),求它的每一个前缀,是否能被表示成(m+1)个字符串(A)(m)个字符串(B)交错相连的形式,即求(forall iin[1,|a|],left[exists A,exists B,a_{1sim i}=underbrace{A+B+A+cdots+A+B+A}_{m+1 ext{个}A,m ext{个}B} ight])

    (|a|inleft[1,10^6 ight])

    考虑把(A+B)看作一个整体,这样问题就转化为了求(a)的每一个前缀是否能被表示成(m)个字符串(S)相连再连上一个(S)的前缀(可以(=varnothing),也可以(=S))。

    我们先考虑怎么在短时间内知道一个(a)的前缀是否可以被表示为(m)(S)相连,如果可以就再往后扩展。这是一个非常经典的问题。设要求的是(a)的前缀(a_{1sim i})。首先,得满足(mmid i),于是我们可以枚举(dfrac im),即(|S|)。然后如果(a_{1sim i-frac im}=a_{1+frac imsim i}),那么(a_{1sim i})可以被表示为(m)(S)相连(这个很好证吧,错位相等)。我们可以拿(a_{1+frac imsim i})去匹配(a_{1sim i-frac im}),这个显然可以哈希,而在枚举(|S|)(a_{1sim i-frac im})永远是(a)的前缀,所以也可以Z算法(如果聪明的读者还不知道Z算法是什么,please点击这个)。

    接下来要考虑如何往后拓展。这个比较简单,往后拓展的那段子串长度一定(in[0,|S|]),并且要与(a)的前缀匹配。这不正是Z算法的专长吗?(min(|S|,z_{a,m|S|+1}))不就是能往后拓展的最长长度吗?这个最长长度也可以哈希+二分,但那复杂度就带(log)了。对了,能往后拓展最长(z_{a,m|S|+1})个,就意味着(forall iin[m|S|,m|S|+z_{a,m|S|+1}])(a_{1sim i})都能被表示成(m+1)个字符串(A)(m)个字符串(B)交错相连的形式,这是个区间答案赋成(1)的操作,可以用线段树或树状数组维护,但更简单的有差分。最后被赋成(1)的次数若(>0),则答案为(1),否则为(0)

    感觉说的不太清楚。。。具体看代码吧(也不一定能看懂啊)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000000;
    int n/*|a|*/,m/*要被表示成m+1个A与m个B交错相连的形式*/;
    char a[N+5];//字符串 
    int z[N+1];//z数组 
    void z_init(){//Z算法 
    	z[1]=n;
    	int zl=0,zr=0; 
    	for(int i=2;i<=n;i++)
    		if(zr<i){
    			while(i+z[i]<=n&&a[i+z[i]]==a[1+z[i]])z[i]++;
    			if(z[i])zl=i,zr=i+z[i]-1;
    		}
    		else if(i+z[i-zl+1]<=zr)z[i]=z[i-zl+1];
    		else{
    			z[i]=zr-i+1;
    			while(i+z[i]<=n&&a[i+z[i]]==a[1+z[i]])z[i]++;
    			zl=i;zr=i+z[i]-1;
    		}
    }
    int d[N+1];//差分数组 
    int main(){
    	cin>>n>>m>>a+1;
    	z_init();
    	for(int i=1;i*m<=n;i++)//枚举|S| 
    		if(z[i+1]>=i*(m-1)){//a[1~i*m]可以被表示为m个S相连 
    //			cout<<i<<" "<<i*m+min(i,z[i*m+1])<<"
    ";
    			d[i*m]++;//往后拓展的左端点差分数组++ 
    			if(i*m+min(i,z[i*m+1])+1<=n)d[i*m+min(i,z[i*m+1])+1]--;//往后拓展的右端点的下一个差分数组-- 
    		}
    	int now=0;
    	for(int i=1;i<=n;i++){
    		now+=d[i];//现在now为i的答案被赋成1的次数 
    		cout<<!!now;//转为bool值 
    	}
    	return 0;
    }
    
  • 相关阅读:
    phpcms新建模板页教程
    Linux方向职业规划
    Codeforces Round #417 (Div. 2)-A. Sagheer and Crossroad
    Codeforces Round #396(Div. 2) A. Mahmoud and Longest Uncommon Subsequence
    ACM hdu 3336 Count the string
    ACM KMP 格式输入导致TLE
    swing JTable 更新数据
    swing JTable
    HashMap 和 HashTable 区别
    Java中next()和nextLine()
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/CodeForces-526D.html
Copyright © 2011-2022 走看看