zoukankan      html  css  js  c++  java
  • P1117 [NOI2016] 优秀的拆分 SA+DP

    题意:

    戳这里

    分析:

    对于要求的东西我们可以 DP 求一下,我们设 (f[i]) 表示以 (i) 结尾的 (AA) 类型的串的个数,(g[i]) 表示以 (i) 开头的 (AA) 类型的串的个数 (ans=sum f[i] imes g[i+1])

    所以我们现在考虑如何求 (f,g) ,首先我们有一个 (n^2) 暴力的想法,直接枚举两个相邻串判相同

    然后我们考虑优化,我们考虑枚举长度(len), 每(len)个点标记一下,显然每一个长度为 (2 imes len) 的串必定会经过两个标记点,那么我们考虑相邻的两个标记点会带来什么贡献,显然对于标记点 (i,j) ,记他们的后缀的 (lcp) 和前缀的 (lcs)

    1. 如果 (lcp+lcs<len) 那么这两个点不会产生 (AA) 类型的串

    2. 如果 (lcp+lcs>=len) 那么如下图所示(图源其他巨佬的博客,侵删)

    粉色串表示第一个合法的 (f) 串,从它开始向后可以一直扩展到绿色荧光笔结尾,这些点都可以作为 (AA) 类型的结尾,那么我们给段区间的每一个点 (f) 都加 1

    褐色串表示后缀,区间同理

    (lcp,lcs) 可以通过 (SA)(ST)(O(nlog))预处理,(O(1)) 查询,然后我们对区间加的操作差分处理,就可以在 (O(nlog)) 的复杂度内求出 (f,g)

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 3e4+5;
    	int t,n;
    	long long ans;
    	char ch[maxn];
    	int lg[maxn],f[maxn],g[maxn];
    	
    	struct suffix_array
    	{
    		int sa[maxn],rk[maxn],ht[maxn][20],cnt[maxn],oldrk[maxn],tmp[maxn],id[maxn];
    		
    		bool check(int x,int y,int k)
    		{
    			return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];
    		}
    		
    		void build()
    		{
    			int num=26;
    			for(int i=1;i<=n;i++) cnt[rk[i]=ch[i]-'a'+1]++;
    			for(int i=1;i<=num;i++) cnt[i]+=cnt[i-1];
    	        for(int i=n;i;i--) sa[cnt[rk[i]]--]=i;
    	        for(int t=1;t<=n;t<<=1)
    	        {
    	            int tot=0;
    	            for(int i=n-t+1;i<=n;i++) id[++tot]=i;
    	            for(int i=1;i<=n;i++) if(sa[i]>t) id[++tot]=sa[i]-t;
    	            tot=0;
    	            memset(cnt,0,sizeof(cnt));
    	            for(int i=1;i<=n;i++) cnt[tmp[i]=rk[id[i]]]++;
    	            for(int i=1;i<=num;i++) cnt[i]+=cnt[i-1];
    	            for(int i=n;i;i--) sa[cnt[tmp[i]]--]=id[i];
    	            memcpy(oldrk,rk,sizeof(rk));
    	            for(int i=1;i<=n;i++) rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
    	            num=tot;
    	        }
    	        for(int i=1,j=0;i<=n;i++)
    	        {
    	            if(j)j--;
    	            while(ch[i+j]==ch[sa[rk[i]-1]+j]) j++;
    	            ht[rk[i]][0]=j;
    	        }
    	        for(int j=1;j<=18;j++)
    	        {
    	            for(int i=1;i+(1<<j)-1<=n;i++)
    	            {
    	                ht[i][j]=min(ht[i][j-1],ht[i+(1<<(j-1))][j-1]);
    	            }
    	        }
    		}
    		
    		int query(int ql,int qr)
    		{
    			int l=min(rk[ql],rk[qr])+1,r=max(rk[ql],rk[qr]);
    			int t=lg[r-l+1];
    			return min(ht[l][t],ht[r-(1<<t)+1][t]);
    		}
    		
    		void clear()
    		{
    			memset(sa,0,sizeof(sa));
    			memset(rk,0,sizeof(rk));
    			memset(cnt,0,sizeof(cnt));
    			memset(ht,0,sizeof(ht));
    			memset(tmp,0,sizeof(tmp));
    		}
    		
    	}s1,s2;
    	
    	void clear()
    	{
    		s1.clear();s2.clear();
    		memset(f,0,sizeof(f));
    		memset(g,0,sizeof(g));
    		ans=0;
    	}
    	
    	void work()
    	{
    		lg[0]=-1;for(int i=1;i<=30000;i++) lg[i]=lg[i>>1]+1;
    		scanf("%d",&t);
    		while(t--)
    		{
    			scanf("%s",ch+1);n=strlen(ch+1);
    			s1.build();
    			reverse(&ch[1],&ch[n+1]);
    			s2.build();
    			for(int len=1;len<=n/2;len++)
    			{
    				for(int i=len,j=i+len;j<=n;i+=len,j+=len)
    				{
    					int lcp=min(s1.query(i,j),len),lcs=min(s2.query(n-i+2,n-j+2),len-1);
    					int tmp=lcp+lcs-len+1;
    					if(lcp+lcs>=len)
    					{
    						g[i-lcs]++;g[i-lcs+tmp]--;
    						f[j+lcp-tmp]++;f[j+lcp]--;
    					}
    				}
    			}
    			for(int i=1;i<=n;i++) f[i]+=f[i-1],g[i]+=g[i-1];
    			for(int i=1;i<n;i++) ans+=1ll*f[i]*g[i+1];
    			printf("%lld
    ",ans);
    			clear();
    		}
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    } 
    
  • 相关阅读:
    10年学到的编程经验总结
    高效阅读源代码指南
    一行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10
    如何用git将项目代码上传到github
    关于[].slice.call(arguments, 1) 的思考
    前端笔试题(一)
    2017年第一波JavaScript前端面试题
    2017前端面试题之综合篇(1)
    2017前端面试题之Js篇(1)
    前后端分离后各自职责
  • 原文地址:https://www.cnblogs.com/youth518/p/14217497.html
Copyright © 2011-2022 走看看