zoukankan      html  css  js  c++  java
  • 笔记-AHOI2013 差异

    AHOI2013 差异


    方法1:SA

    先板个后缀数组(带 (height) 不带 (st) 表),用单调队列递推每个后缀 (sa_i) 对答案的贡献,求和,用定值减之。

    #include <bits/stdc++.h>
    using namespace std;
    
    //Start
    typedef long long ll;
    typedef double db;
    #define mp(a,b) make_pair(a,b)
    #define x first
    #define y second
    #define b(a) a.begin()
    #define e(a) a.end()
    #define sz(a) int((a).size())
    #define pb(a) push_back(a)
    const int inf=0x3f3f3f3f;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    
    //Data
    const int N=5e5;
    int n;
    char s[N+7];
    
    //SuffixArray
    int m,c[N+7],tp[N+7],rk[N+7],sa[N+7],h[N+7];
    void csort(){
    	for(int i=0;i<=m;i++) c[i]=0;
    	for(int i=1;i<=n;i++) c[rk[i]]++;
    	for(int i=1;i<=m;i++) c[i]+=c[i-1];
    	for(int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
    }
    void build(){
    	for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
    	m=128,csort();
    	for(int w=1,p=1,i;p<n;w<<=1,m=p){
    		for(p=0,i=n-w+1;i<=n;i++) tp[++p]=i;
    		for(i=1;i<=n;i++)if(sa[i]>w) tp[++p]=sa[i]-w;
    		csort(),swap(rk,tp),rk[sa[1]]=p=1;
    		for(i=2;i<=n;rk[sa[i]]=p,i++)
    			if(tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+w]!=tp[sa[i-1]+w]) p++;
    	}
    	for(int i=1,j,k=0;i<=n;h[rk[i++]]=k)
    		for(k=k?k-1:k,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
    }
    
    //Main
    int main(){
    	scanf("%s",&s[1]);
    	n=strlen(&s[1]),build();
    	vector<int> q(n+7); int lst=0,qc=0;
    	vector<ll> f(n+7); ll res=0;
    	for(int i=1;i<=n;i++){
    		while(qc&&h[q[qc]]>h[i]) qc--;
    		int j=qc?q[qc]:lst;
    		res+=(f[i]=f[j]+1ll*(i-j)*h[i]);
    		if(!h[i]) lst=i;
    		else q[++qc]=i;
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d ",sa[i]);puts("");
    	for(int i=1;i<=n;i++)
    		printf("%d ",h[i]);puts("");
    	for(int i=1;i<=n;i++)
    		printf("%lld ",f[i]);puts("");
    	printf("%lld
    ",1ll*(n-1)*n*(n+1)/2-res*2);
    	return 0;
    }
    
    

    方法2:SAM

    注意到这个式子是 ( t SAM) (f parent~tree) 树上两点的距离,计算每条边的贡献和即可。

    SAM.jpg

    #include <bits/stdc++.h>
    using namespace std;
    
    //Start
    typedef long long ll;
    typedef double db;
    #define mp(a,b) make_pair(a,b)
    #define x first
    #define y second
    #define b(a) a.begin()
    #define e(a) a.end()
    #define sz(a) int((a).size())
    #define pb(a) push_back(a)
    const int inf=0x3f3f3f3f;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    
    //Data
    const int N=5e5;
    int n;
    char s[N+7];
    ll ans;
    
    //SuffixAutomata
    const int T=(N<<1);
    int cnt=1,en=1,ch[T+7][26],fa[T+7],dep[T+7],sz[T+7];
    int c[T+7],q[T+7];
    void insert(int c){
        int p=en,np=++cnt;
        dep[en=np]=dep[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(dep[q]==dep[p]+1) fa[np]=q;
            else {
                int nq=++cnt;
                dep[nq]=dep[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        sz[np]=1;
    }
    void run(){
        for(int i=1;i<=cnt;i++) c[i]=0;
        for(int i=1;i<=cnt;i++) c[dep[i]]++;
        for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
        for(int i=1;i<=cnt;i++) q[c[dep[i]]--]=i;
        for(int i=cnt;i>=1;i--){
        	int p=q[i];
            sz[fa[p]]+=sz[p];
            ans+=1ll*(dep[p]-dep[fa[p]])*sz[p]*(n-sz[p]);
        }
    }
    
    //Main
    int main(){
    	scanf("%s",&s[1]),n=strlen(&s[1]);
    	for(int i=1;i<=n;i++) insert(s[i]-'a');
    	run();
    	printf("%lld
    ",ans);
        return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    74. Search a 2D Matrix(js)
    73. Set Matrix Zeroes(js)
    72. Edit Distance(js)
    71. Simplify Path(js)
    兼容各种浏览器版本的事件绑定函数?
    浏览器兼容性问题
    柯里化函数
    token登录验证机制
    vue懒加载
    在Vue中使用了Swiper ,动态从后台获取数据的之后,swiper滑动失效??
  • 原文地址:https://www.cnblogs.com/Wendigo/p/12925837.html
Copyright © 2011-2022 走看看