zoukankan      html  css  js  c++  java
  • SA

    rk 排名,相同的排名相同
    sa 排名的位置, 如果相同按位置顺序
    y 辅助第二关键字
    c 桶
    理解
    Q:为什么不可以将rk相同的按位置顺序变成不同的
    A:这样如果第一关键字相同时比较第二关键字答案相反,就会有问题,如果这样对的,你的字典序在一开始就排好了
    Q:y[sa[i]+k]不会越界吗?
    A:如果越界前面的sa肯定会不同,因为长度不同,极限只有在最后一位会刚好多出一位,所以要多清一位

    有些东西还是应该理解的深刻一点,而不是一味的学习,一味的赶进度

    关于Height
    把第i个串嵌到第i - 1个串去思考,然后就会发现存在另一个串与他相近,然后就让目标串夹在中间
    证得 Height[i] >= Height[i - 1] - 1

    #include<bits/stdc++.h>
    
    #define rep(x, L, R) for(int x = (L), _x = (R); x <= _x; x++)
    #define per(x, R, L) for(int x = (R), _x = (L); x >= _x; x--)
    #define forgp(u, g, v) for(int iu = 0, v; iu < (int)g[u].size() && (v = g[u][iu], 1); iu++)
    #define mp make_pair
    #define siz(v) (int)(v).size()
    #define x first
    #define y second
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef long long ll;
    typedef double db;
    const int N = 1e6 + 10;
    int n;
    char s[N];
    int heg[N];
    int sa[N], rk[N], c[N], y[N], m;
    
    void SA(char *s, int n) {
    	m = 256;
    	rep(i, 1, n) {
    		c[rk[i] = s[i]]++;
    	}
    	rep(i, 1, m) c[i] += c[i - 1];
    	per(i, n, 1) {
    		sa[c[rk[i]]--] = i;
    	}
    	for(int k = 1; k < n; k <<= 1) {
    		int p = 0;
    		rep(i, n - k + 1, n) y[++p] = i;
    		rep(i, 1, n) if(sa[i] - k > 0) y[++p] = sa[i] - k;
    		rep(i, 0, m) c[i] = 0;
    		rep(i, 1, n) c[rk[y[i]]]++;
    		rep(i, 1, m) c[i] += c[i - 1];
    		per(i, n, 1) sa[c[rk[y[i]]]--] = y[i];
    		p = 0;
    		swap(rk, y);
    		rk[sa[1]] = ++p;
    		rep(i, 2, n) {
    			rk[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
    		}
    		m = p;
    		if(m >= n) break;
    	}
    	return;
    }
    
    void Heg(int n) {
    	rep(i, 1, n) heg[i] = 0;
    	rep(i, 1, n) {
    		if(rk[i] == 1) continue;
    		int p = sa[rk[i] - 1];
    		int k = max(0, h[a[i - 1]] - 1);
    		while(i + k <= n && p + k <= n && s[i + k] == s[p + k]) k++;
    		heg[rk[i]] = k;
    	}
    	return;
    }
    
    int main() {
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	return 0;
    }
    
    
    
    
    
    

    题目

    [NOI2016]优秀的拆分

    #include<bits/stdc++.h>
    using namespace std;
    const int N=31000;
    const int Log=15;
    char ch[N];
    int T,n;
    int l2[N];
    int p2[Log+5];
    int f[N],g[N];
    struct SA
    {
    	int n;
    	char ch[N];
    	int a[N],t[N],sa[N],c[N],m;
    	int h[N];
    	int st[Log+5][N];	
    	void getst()
    	{
    		for(int i=1;i<=n;i++) st[0][i]=h[i];
    		for(int i=1;i<=Log;i++)
    			for(int j=1;j+p2[i]-1<=n;j++)
    				st[i][j]=min(st[i-1][j],st[i-1][j+p2[i-1]]);
    		return; 
    	}
    	int LCP(int l,int r)
    	{
    		l=a[l],r=a[r];
    		if(l>r) swap(l,r);
    		l++;
    		int len=r-l+1;
    		len=l2[len];
    		return min(st[len][l],st[len][r-p2[len]+1]);
    	}
    	void getsa()
    	{
    		m=256;
    		for(int i=0;i<=m;i++) c[i]=0;
    		for(int i=1;i<=n;i++) c[a[i]=ch[i]]++;
    		for(int i=1;i<=m;i++) c[i]+=c[i-1];
    		for(int i=n;i>=1;i--) sa[c[a[i]]--]=i;
    		for(int k=1;k<=n;k<<=1)
    		{
    			int p=0;
    			for(int i=n-k+1;i<=n;i++) t[++p]=i;
    			for(int i=1;i<=n;i++) if(sa[i]>k) t[++p]=sa[i]-k;
    			for(int i=0;i<=m;i++) c[i]=0;
    			for(int i=1;i<=n;i++) c[a[i]]++;
    			for(int i=1;i<=m;i++) c[i]+=c[i-1];
    			for(int i=n;i>=1;i--) sa[c[a[t[i]]]--]=t[i];
    			swap(a,t),p=1,a[sa[1]]=1;
    			for(int i=2;i<=n;i++) a[sa[i]]=(t[sa[i]]==t[sa[i-1]]&&sa[i]+k<=n&&sa[i-1]+k<=n&&t[sa[i]+k]==t[sa[i-1]+k])?p:++p;
    			if(p>=n) break;
    			m=p;
    		}
    		return;
    	}
    	void geth()
    	{
    		for(int i=0;i<=n;i++) h[i]=0;
    		for(int i=1;i<=n;i++)
    		{
    			if(a[i]==1) continue;
    			int x=sa[a[i]-1];
    			int k=max(0,h[a[i-1]]-1);
    			while(max(i,x)+k<=n&&ch[i+k]==ch[x+k]) k++;
    			h[a[i]]=k;
    		}
    		return;
    	}
    	void Init(char *s)
    	{
    		n=strlen(s+1);
    		for(int i=1;i<=n;i++) ch[i]=s[i];
    		ch[n+1]='';
    		getsa();
    		geth();
    		getst();
    		return;
    	}
    };
    SA suf,pre;
    int S(int x)
    {
    	return x;
    }
    int P(int x)
    {
    	return n+1-x;
    }
    void tag(int l,int r,int *s)
    {
    	if(l<1) l=1;
    	if(r>n) r=n;
    	if(l>r) return;
    	s[l]++,s[r+1]--;
    	return;
    }
    long long sol()
    {
    	for(int i=0;i<=n+1;i++) f[i]=0,g[i]=0;
    	for(int len=1;len<=n;len++)
    	{
    		for(int i=len;i+len<=n;i+=len)  
    		{
    			int l=i+1,r=i+len;
    			int su=suf.LCP(S(i),S(i+len)),pr=pre.LCP(P(i),P(i+len));
    			l=max(l,i+len-pr+1);
    			r=min(r,i+su);
    //			cout<<i<<" "<<len<<" "<<su<<" "<<pr<<" "<<l<<" "<<r<<endl;
    			tag(l-len,r-len,g);
    			tag(l+len-1,r+len-1,f);
    		}
    	}
    	long long ans=0;
    	for(int i=1;i<=n;i++) f[i]+=f[i-1],g[i]+=g[i-1];
    //	for(int i=1;i<=n;i++) cout<<f[i]<<" "<<g[i]<<endl;
    	for(int i=2;i<=n;i++) ans+=f[i-1]*g[i];
    	return ans;
    }
    int main()
    {
    	p2[0]=1;
    	for(int i=1;i<=Log;i++) p2[i]=p2[i-1]<<1;
    	l2[0]=-1;
    	for(int i=1;i<=3e4;i++) l2[i]=l2[i/2]+1;
    	scanf("%d",&T); 
    	for(int am=1;am<=T;am++)
    	{
    		scanf("%s",ch+1);
    		n=strlen(ch+1);
    		suf.Init(ch);
    		reverse(ch+1,ch+n+1);
    		pre.Init(ch);
    		printf("%lld
    ",sol());
    	}
    	return 0;
    } 
    
  • 相关阅读:
    金融学专业排名
    学经济学专业排行榜
    国内,美国数学专业排名
    为什么国外程序员爱用苹果 Mac 电脑?
    计算机专业-世界大学学术排名,QS排名,U.S.NEWS排名
    基金合作伙伴
    融资晚报:一大波创业公司获得融资
    有哪些适合学生参与的 C++,网络编程方面的开源项目?
    SuperSocket内置的命令行协议的解析
    C# Socket 您的主机中的软件中止了一个已建立的连接 An established connection was aborted by the software in your host machine
  • 原文地址:https://www.cnblogs.com/SegmentTree/p/13052796.html
Copyright © 2011-2022 走看看