zoukankan      html  css  js  c++  java
  • CF1276F

    题目大意

    给出一个串S,求将至多一个位置换成*后所有串的不同子串个数

    |S|<=1e5

    题解

    比E阳间得多但是并不是很好写

    开始想枚举开头然后考虑星号位置,然后发现不可做

    换一种思路,从大到小枚举星号前面的长度,那么变成新的问题:

    每次动态加入一个S的后缀,或者把两个后缀集合合并,不同集合的串一定不同,求不同的前缀个数

    不同的个数等于总数-相邻的lcp,所以显然可以set启发式合并,加入的时候删掉原来的lcp加上新的lcp

    加入的时间根据反串的SA求,注意加到set里面的是rank否则算的lcp不对

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    int p[18],c[100001],d[100001],fa[100001],sum[100001],n,i,j,k,l,tot,x,y,t;
    set<int> S[100001];
    set<int> :: iterator I,J,K;
    char st[100001];
    ll ans,Ans;
    struct type{int t,x,y;} b[200001];
    void swap(int &x,int &y) {int z=x;x=y;y=z;}
    int gf(int t) {if (fa[t]==t) return t;fa[t]=gf(fa[t]);return fa[t];}
    struct SA{
    	int hi[200001],Hi[100001][17],sa[200001],ls[200001],rk[200001],Rk[200001],h[200001],a[200001],b[200001],i,j,k,l;
    	char st[200001];
    	
    	void add()
    	{
    		static int a[200001],b[200001];
    		int i,j,k,l;
    		
    		memset(a,0,sizeof(a));memset(b,0,sizeof(b));
    		fo(i,1,n) ++a[rk[i]];
    		fo(i,1,n) a[i]+=a[i-1];
    		fo(i,1,n) ++b[rk[i]],sa[a[rk[i]-1]+b[rk[i]]]=i;
    	}
    	void Add(int t)
    	{
    		b[rk[t]]+=rk[t+l]!=ls[rk[t]],ls[rk[t]]=rk[t+l];
    		Rk[t]=a[rk[t]-1]+b[rk[t]];
    	}
    	void init()
    	{
    		l=1;
    		fo(i,1,n) a[st[i]-'a']=1;
    		fo(i,1,25) a[i]+=a[i-1];
    		fo(i,1,n) rk[i]=a[st[i]-'a'];
    		add();
    		while (l<n)
    		{
    			memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(ls,128,sizeof(ls));
    			fo(i,1,n) ++a[rk[i]];
    			fo(i,1,n) a[i]+=a[i-1];
    			fo(i,n-l+1,n) Add(i);
    			fo(i,1,n) if (sa[i]-l>=1) Add(sa[i]-l);
    			
    			memcpy(rk,Rk,sizeof(Rk));memset(a,0,sizeof(a));
    			fo(i,1,n) a[rk[i]]=1;
    			fo(i,1,n) a[i]+=a[i-1];
    			fo(i,1,n) rk[i]=a[rk[i]];
    			add();
    			l*=2;
    		}
    		
    		while (rk[1]<n && max(1,sa[rk[1]+1])+h[1]-1<n && st[1+h[1]]==st[sa[rk[1]+1]+h[1]]) ++h[1];
    		fo(i,2,n)
    		{
    			h[i]=max(h[i-1]-1,0);
    			if (rk[i]==n) h[i]=0;
    			else
    			{while (max(i,sa[rk[i]+1])+h[i]-1<n && st[i+h[i]]==st[sa[rk[i]+1]+h[i]]) ++h[i];}
    		}
    		fo(i,1,n) hi[rk[i]]=h[i];
    		
    		fo(i,1,n-1) Hi[i][0]=hi[i];l=1;j=0;
    		while (l*2<=n-1)
    		{
    			++j;
    			fo(i,1,(n-1)-l*2+1) Hi[i][j]=min(Hi[i][j-1],Hi[i+l][j-1]);
    			l*=2;
    		}
    	}
    	int get(int x,int y) {if (x>y) swap(x,y);--y; int l=floor(log2(y-x+1)); return min(Hi[x][l],Hi[y-p[l]+1][l]);}
    } s1,s2;
    bool cmp(type a,type b) {return a.t>b.t || a.t==b.t && a.y<b.y;}
    
    int main()
    {
    	#ifdef file
    	freopen("cf1276F.in","r",stdin);
    	#endif
    	
    	p[0]=1;fo(i,1,17) p[i]=p[i-1]*2;
    	scanf("%s",st+1),n=strlen(st+1);
    	fo(i,1,n) s1.st[i]=st[i],s2.st[n-i+1]=st[i],fa[i]=i;
    	s1.init();s2.init();
    	
    	ans=2;
    	if (n>=3)
    	{
    		fo(i,1,n-2) b[++tot]={i,s1.rk[i+2],0},c[i]=s2.rk[n-i+1];
    		sort(c+1,c+(n-2)+1);
    		fo(i,1,n-3) {j=s2.get(c[i],c[i+1]); if (j) b[++tot]={j,s1.rk[n-s2.sa[c[i]]+3],s1.rk[n-s2.sa[c[i+1]]+3]};}
    		sort(b+1,b+tot+1,cmp);
    		
    		l=0;
    		fo(i,1,tot)
    		if (i==tot || b[i].t!=b[i+1].t)
    		{
    			fo(j,l+1,i)
    			if (!b[j].y)
    			{
    				Ans+=n-s1.sa[b[j].x]+1;
    				sum[s1.sa[b[j].x]]=1;S[s1.sa[b[j].x]].insert(b[j].x);
    			}
    			else
    			{
    				x=gf(s1.sa[b[j].x]),y=gf(s1.sa[b[j].y]);
    				if (sum[x]<sum[y]) swap(x,y);
    				
    				t=0;
    				for (I=S[y].begin(); I!=S[y].end(); ++I)
    				{
    					d[++t]=*I;
    					K=S[x].upper_bound(*I);
    					if (K!=S[x].end())
    					{
    						Ans-=s1.get(*I,*K);
    						if (K!=S[x].begin())
    						{
    							J=K;--J;
    							Ans+=s1.get(*J,*K)-s1.get(*J,*I);
    						}
    					}
    					else
    					J=K,--J,Ans-=s1.get(*J,*I);
    					S[x].insert(*I);
    				}
    				fo(k,1,t-1) Ans+=s1.get(d[k],d[k+1]);
    				fa[y]=x;sum[x]+=sum[y];
    			}
    			l=i;
    			ans+=Ans*(b[i].t-b[i+1].t);
    		}
    	}
    	if (n>=2)
    	{
    		fo(i,2,n) c[i-1]=s1.rk[i];
    		sort(c+1,c+(n-1)+1);
    		fo(i,1,n-1)
    		{
    			ans+=n-s1.sa[c[i]]+1;
    			if (i<n-1) ans-=s1.get(c[i],c[i+1]);
    		}
    		fo(i,1,n-1) c[i]=s2.rk[n-i+1];
    		sort(c+1,c+(n-1)+1);
    		fo(i,1,n-1)
    		{
    			ans+=n-s2.sa[c[i]]+1;
    			if (i<n-1) ans-=s2.get(c[i],c[i+1]);
    		}
    	}
    	fo(i,1,n)
    	{
    		ans+=n-s1.sa[i]+1;
    		if (i<n) ans-=s1.hi[i];
    	}
    	
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    redis接入sentinelPool的配置
    02.Redis主从集群的Sentinel配置
    淘宝大秒系统设计详解
    关于Thread.currentThread()和this的差异
    App开放接口api安全性—Token签名sign的设计与实现
    使用Spring Session做分布式会话管理
    PowerDesigner 15.1 安装步骤详细图解及破解
    解密ThreadLocal
    深入分析 ThreadLocal 内存泄漏问题
    一个经典例子让你彻彻底底理解java回调机制
  • 原文地址:https://www.cnblogs.com/gmh77/p/13460372.html
Copyright © 2011-2022 走看看