zoukankan      html  css  js  c++  java
  • [BZOJ2806] [CTSC2012] Cheat

    Description

    img

    img

    Input

    第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库
    的行数
    接下来M行的01串,表示标准作文库
    接下来N行的01串,表示N篇作文

    Output

    N行,每行一个整数,表示这篇作文的Lo 值。

    Sample Input

    1 2
    10110
    000001110
    1011001100
    

    Sample Output

    4
    

    Solution

    神题。

    首先把模式串建出广义后缀自动机,由于我不会这个就只好把串用特殊符号连起来然后建单串(SAM)了...这玩意比较容易被卡的,这题字符集很小串长也很小就没啥问题。

    然后对于匹配串预处理出一个(maxlen[i])表示第(i)位结尾的最长公共子串长度,这个可以在自动机上跑出来,具体的,沿着自动机走,如果走到了一个非法状态就条(parent)状态转移回去,然后长度就变成了(maxl+1)

    注意到(L)是满足可二分性的,所以可以先二分答案。

    然后对于这种切成一段段的区间的问题可以考虑一个(O(n^2))(dp)加玄学优化。

    这里就设(f[i])表示考虑了前(i)个点的答案,然后可以得到一个很显然的转移:

    [f[i]=max(f[i-1],max_{j=i-maxlen[i]}^{i-L}{f[j]+i-j}) ]

    注意到决策点是单调不降的,并且(i)也是单增的,那么就可以用一个单调队列来维护(f[j]-j)

    时间复杂度(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 2e6+10;
    
    char s[maxn];
    int n,m,qs=1,cnt=1,lstp=1,len,head,tail;
    int par[maxn],tr[maxn][3],ml[maxn],mxlen[maxn],f[maxn];
    
    void append(int c) {
    	int p=lstp,np=++cnt;ml[np]=ml[p]+1;lstp=np;
    	for(;p&&tr[p][c]==0;p=par[p]) tr[p][c]=np;
    	if(!p) return par[np]=qs,void();
    	int q=tr[p][c];
    	if(ml[p]+1<ml[q]) {
    		int nq=++cnt;ml[nq]=ml[p]+1;
    		memcpy(tr[nq],tr[q],sizeof tr[nq]);
    		par[nq]=par[q],par[q]=par[np]=nq;
    		for(;p&&tr[p][c]==q;p=par[p]) tr[p][c]=nq;
    	} else par[np]=q;
    }
    
    int q[maxn];
    
    void get_mxlen() {
    	int now=qs,res=0;
    	for(int i=1,v;i<=len;i++) {
    		if(tr[now][v=s[i]-'0']) now=tr[now][v],res++;
    		else {
    			for(;now&&tr[now][v]==0;now=par[now]);
    			if(!now) now=qs,res=0;else res=ml[now]+1,now=tr[now][v];
    		}
    		mxlen[i]=res;
    	}
    }
    
    int check(int L) {
    	head=1,tail=0;
    	for(int i=0;i<L;i++) f[i]=0;
    	for(int i=L;i<=len;i++) {
    		f[i]=f[i-1];
    		while(head<=tail&&f[q[tail]]-q[tail]<f[i-L]-i+L) tail--;
    		q[++tail]=i-L;
    		while(head<=tail&&q[head]<i-mxlen[i]) head++;
    		if(head<=tail) f[i]=max(f[i],f[q[head]]-q[head]+i);
    	}return len*9<=f[len]*10;
    }
    
    int main() {
    	read(n),read(m);
    	for(int i=1;i<=m;i++) {
    		scanf("%s",s+1);int l=strlen(s+1);append(2);
    		for(int j=1;j<=l;j++) append(s[j]-'0');
    	}
    	for(int T=1;T<=n;T++) {
    		scanf("%s",s+1);
    		int l=0,r=strlen(s+1),mid,ans=0;
    		len=r;get_mxlen();
    		while(l<=r) if(check(mid=(l+r)>>1)) l=mid+1,ans=mid;else r=mid-1;
    		write(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Oracle 11g 在本机上安装PLSQL DEveloper
    Oracle 11g 启动与关闭服务的脚本
    Oracle 11g 安装过程图解
    linux下vi命令大全
    accuracy、precision、recall、true positives, true negatives, false positives 和 false negatives
    // 40、用1、2、2、3、4、5这六个数字,写一个main函数,打印出所有不同的排列, // 如:512234、412345等,要求:"4"不能在第三位,"3"与"5"不能相连.
    阿里巴巴第二道(研发类) 笔试题1,原题大致描述有一大批数据,百万级别的。数据项内容是:用户ID、科
    621. Task Scheduler
    625. Minimum Factorization
    623. Add One Row to Tree
  • 原文地址:https://www.cnblogs.com/hbyer/p/10436327.html
Copyright © 2011-2022 走看看