zoukankan      html  css  js  c++  java
  • 【loj2064】找相同字符

    Portal --> loj2064

    Solution

      这里是用后缀数组做的版本!(晚点再用Sam写一遍qwq)

    ​  首先一个字符串的子串其实就是这个字符串某个后缀的前缀,所以我们有一个十分简单粗暴的想法直接把两个串接起来(常用套路:中间加一个最大的字符作为分隔符)然后求Sa,求完之后我们就可以十分愉快地获得一个(O(n^2))的算法了(每次枚举两个后缀,然后经过预处理之后我们可以用ST表(O(1))求得lcp,答案显然就是这堆lcp之和)

      然而(O(n^2))十分不优秀,这里我们可以反过来想每一个(height[i])可以在哪一个范围内作为最小值,具体的话我们可以用递归来实现

      为了方便表示,我们记(cnt1[i])表示排名前(i)的后缀中,属于第一个串的后缀数量,(cnt2[i])表示排名前(i)的后缀中,属于第二个串的后缀数量

      记(solve(l,r))表示处理(rk)(in [l,r])的这堆后缀对答案的贡献,我们可以用ST表求的这个区间内的(height)最小值为(x),然后我们记这个最小值的位置为(mid),那么这个区间内长度为(x)的取法对答案的贡献就是

    [egin{aligned} x&*((cnt1[mid-1]-cnt1[l-1])*(cnt2[r]-cnt2[mid-1])+(cnt2[mid-1]-cnt2[l-1])*(cnt1[r]-cnt1[mid-1])) end{aligned} ]

      然后接着我们直接递归处理([l,mid-1])区间和([mid,r])区间就好了(其实好像区间这个加减的东西可以自己调整一下。。不过相对应的上面的式子中(cnt1)(cnt2)的范围也需要稍微调整一下,都是具体实现个人习惯的问题)

      注意答案可能比较大所以需要用long long

      

      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define Pr pair<int,int>
    #define mp make_pair
    using namespace std;
    const int N=200010,SA=N*2,TOP=20;
    char s1[N],s2[N],s[N*2];
    int n1,n2,n;
    ll ans;
    namespace Sa{/*{{{*/
    	int a[SA],b[SA],c[SA],sa[SA],rk[SA],height[SA];
    	int mn[SA][TOP+1],loc[SA][TOP+1];
    	int cnt1[SA],cnt2[SA];
    	int mx;
    	bool cmp(int x,int y,int len,int *r)
    	{return r[x]==r[y]&&r[x+len]==r[y+len];}
    	void sort(int n){
    		for (int i=0;i<=mx;++i) c[i]=0;
    		for (int i=1;i<=n;++i) ++c[a[b[i]]];
    		for (int i=1;i<=mx;++i) c[i]+=c[i-1];
    		for (int i=n;i>=1;--i) sa[c[a[b[i]]]--]=b[i];
    	}
    	void get_sa(int n){
    		mx=0;
    		for (int i=1;i<=n;++i) a[i]=s[i]-'a'+1,mx=max(mx,a[i]),b[i]=i;
    		sort(n);
    		int cnt=0;
    		for (int len=1;cnt<n;len<<=1){
    			cnt=0;
    			for (int i=n-len+1;i<=n;++i) b[++cnt]=i;
    			for (int i=1;i<=n;++i)
    				if (sa[i]>len)
    					b[++cnt]=sa[i]-len;
    			sort(n);
    			swap(a,b);
    			cnt=1; a[sa[1]]=1;
    			for (int i=2;i<=n;a[sa[i++]]=cnt)
    				if (!cmp(sa[i],sa[i-1],len,b)) ++cnt;
    			mx=cnt;
    		}
    	}
    	void rmq(int n){
    		for (int i=1;i<=n;++i) mn[i][0]=height[i],loc[i][0]=i;
    		for (int j=1;(1<<j)<=n;++j)
    			for (int i=n-(1<<j)+1;i>=1;--i){
    				if (mn[i][j-1]<mn[i+(1<<j-1)][j-1])
    					mn[i][j]=mn[i][j-1],loc[i][j]=loc[i][j-1];
    				else
    					mn[i][j]=mn[i+(1<<j-1)][j-1],loc[i][j]=loc[i+(1<<j-1)][j-1];
    			}
    	}
    	void get_height(int n){
    		for (int i=1;i<=n;++i) rk[sa[i]]=i;
    		int k=0;
    		for (int i=1;i<=n;++i){
    			if (k) --k;
    			while (s[i+k]==s[sa[rk[i]-1]+k]) ++k;
    			height[rk[i]]=k;
    		}
    		rmq(n);
    	}
    	Pr Lcp(int x,int y){//x y are ranks
    		if (x==y) return mp(n-sa[x]+1,x);
    		++x;
    		if (x>y) swap(x,y);
    		int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0));
    		if (mn[x][lg]<mn[y-(1<<lg)+1][lg]) return mp(mn[x][lg],loc[x][lg]);
    		return mp(mn[y-(1<<lg)+1][lg],loc[y-(1<<lg)+1][lg]);
    	}
    	void pre_calc(int n,int n1){
    		for (int i=1;i<=n;++i){
    			cnt1[i]=cnt1[i-1];
    			cnt2[i]=cnt2[i-1];
    			if (sa[i]<n1) ++cnt1[i];
    			else if (sa[i]>n1) ++cnt2[i];
    		}
    	}
    	void get_ans(int l,int r){
    		if (l>=r) return;
    		Pr tmp=Lcp(l,r);
    		int mid=tmp.second,lcp=tmp.first;
    		ans+=1LL*lcp*(1LL*(cnt1[mid-1]-cnt1[l-1])*(cnt2[r]-cnt2[mid-1])+1LL*(cnt2[mid-1]-cnt2[l-1])*(cnt1[r]-cnt1[mid-1]));
    		get_ans(l,mid-1);
    		get_ans(mid,r);
    	}
    }/*}}}*/
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%s
    %s",&s1,&s2);
    	n1=strlen(s1);
    	n2=strlen(s2);
    	n=0;
    	for (int i=0;i<n1;++i) s[++n]=s1[i];
    	s[++n]='z'+1;
    	for (int i=0;i<n2;++i) s[++n]=s2[i];
    	Sa::get_sa(n);
    	Sa::get_height(n);
    	Sa::pre_calc(n,n1+1);
    	ans=0;
    	Sa::get_ans(1,n);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    POJ 2027
    POJ 2017
    重定位(转载)
    常见储存器件的分辨(RAM、SRAM、SDRAM、ROM、FLASH、Nand Flash、Nor Flash、DDR、eMMC)
    虚拟机安装配置ubuntu共享文件夹
    ARM芯片时钟体系
    串行通信协议 —— UART
    串行通信协议——基础知识
    内存地址和内存空间
    中断与异常
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9368564.html
Copyright © 2011-2022 走看看