zoukankan      html  css  js  c++  java
  • 题解-CTSC2012 熟悉的文章

    Problem

    bzoj

    题目大意:给定多个标准串和一个文本串,全部为01串,如果一个串长度不少于(L)且是任意一个标准串的子串,那么它是“熟悉”的。对于文本串(A),把(A)分割成若干段子串,其中“熟悉”的子串的长度总和不少于(A)总长度的(90\%),那么该(L)是可行的。求可行的(L)最大值

    Solution

    前置技能:二分答案、SAM、Dp、单调队列

    字符串长在L上下对答案贡献是断崖式的,按套路二分L

    再根据对序列分段问题的直觉可以得到dp方程:(f[i]=max(f[i-1],f[j]+i-j),jleq i-L且s[j…i]是熟悉的)

    这样复杂度加上各种优化是(O(n^2))(O(n^3))不等的

    考虑到对于(i),合法的(j)一定是连续的,可以用后缀自动机预处理出每一个字符(i)向左最长的熟悉的串位置(orz[i])

    dp方程为:(f[i]=max(f[i-1],f[j]+i-j),jin[i-orz[i],i-L])

    发现dp方程可以用单调队列优化:队列里存(f[i]-i)即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define rg register
    
    const int N=2001000;
    int pre[N],stp[N],ch[N][2];
    int f[N],q[N],orz[N];
    int n,m,len,tot=1,lst=1,L,R;
    char s[N];
    
    inline void ins(int x){
    	int p=lst,np=++tot;
    	lst=np;stp[np]=stp[p]+1;
    	while(p&&!ch[p][x])ch[p][x]=np,p=pre[p];
    	if(!p)pre[np]=1;
    	else {
    		int q=ch[p][x];
    		if(stp[q]==stp[p]+1)pre[np]=q;
    		else {
    			int nq=++tot;stp[nq]=stp[p]+1;
    			//*ch[nq]=*ch[q];
    			ch[nq][0]=ch[q][0],ch[nq][1]=ch[q][1];
    			pre[nq]=pre[q];
    			pre[q]=pre[np]=nq;
    			while(ch[p][x]==q)ch[p][x]=nq,p=pre[p];
    		}
    	}return ;
    }
    
    inline int check(int li){
    	int he(1),ta(0);
    	for(rg int i=1;i<=len;++i){
    		f[i]=f[i-1];
    		if(i<li)continue;
    		while(he<=ta&&f[q[ta]]-q[ta]<=f[i-li]-i+li)--ta;
    		q[++ta]=i-li;
    		while(he<=ta&&q[he]<i-orz[i])++he;
    		if(he<=ta)f[i]=max(f[i],f[q[he]]+i-q[he]);
    	}return f[len]*10>=len*9;
    }
    
    void PRE(){
    	scanf("%s",s+1);
    	len=strlen(s+1);
    	L=0;R=len;
    	int nw(1),cnt(0);
    	for(rg int i=1;i<=len;++i){
    		int x=s[i]-'0';
    		if(ch[nw][x])++cnt,nw=ch[nw][x];
    		else {
    			while(nw&&!ch[nw][x])nw=pre[nw];
    			if(nw)cnt=stp[nw]+1,nw=ch[nw][x];
    			else nw=1,cnt=0;
    		}
    		orz[i]=cnt;
    	}return ;
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	while(m--){
    		scanf("%s",s);lst=1;
    		for(rg int i=0;s[i];++i)ins(s[i]-'0');
    	}
    	while(n--){
    		PRE();
    		while(L<R){
    			int mid(L+R+1>>1);
    			if(check(mid))L=mid;
    			else R=mid-1;
    		}
    		printf("%d
    ",L);
    	}return 0;
    }
    
  • 相关阅读:
    237. Delete Node in a Linked List
    430. Flatten a Multilevel Doubly Linked List
    707. Design Linked List
    83. Remove Duplicates from Sorted List
    160. Intersection of Two Linked Lists
    426. Convert Binary Search Tree to Sorted Doubly Linked List
    142. Linked List Cycle II
    类之间的关系
    初始化块
    明确类和对象
  • 原文地址:https://www.cnblogs.com/penth/p/9233454.html
Copyright © 2011-2022 走看看