• 【loj2033】生成魔咒


    Portal --> loj2033

    Solution

      这题。。虽然说好像也是sam的裸题不过既然在智力康复那就强制后缀数组吧qwq

    ​  (晚点再用sam写一次qwq)

      首先如果是要求本质不同的串的数量的话,如果说只用求一次,那么我们直接跑出这个串的(Sa)(height),然后直接对于每一位(i)(ans+=(n-sa[i]+1)-height[i]),具体的话可以看这里Portal-->

    ​  然后现在的问题是。。每加入一个字符我们都需要这么求一次

    ​  那么我们可以考虑将这个串反过来,这样往末端加字符的操作就变成了往前段加字符,也就是变成了多加一个后缀,这样我们就可以比较好处理这个问题了

    ​  我们先对原串的反串求出(Sa)(height),然后用一个set或者。。额其实链表也是可以的来维护当前有哪些后缀(存(rk)值就好了),顺序按照这些后缀的(rk)值来排,每次我们找到插入当前这个后缀的位置,记加入这个后缀之后,前面的那个位置的(rk)值为(pre),后面那个位置的(rk)值为(nxt),那么我们就将原来的贡献(也就是((n-sa[nxt]+1)-lcp(pre,nxt)))减去,然后将新的贡献也就是当前后缀和(pre)的贡献、当前后缀和(nxt)的贡献加上,一直这么操作就好了

    ​  需要注意的是,这里要用long long,并且一开始的时候(set)中应该有一个(0),这样才能将第一个后缀的贡献算进去,以及因为数字(x)的范围有点吓人所以我们需要离散化一下

      

      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #define ll long long
    using namespace std;
    const int N=1e5+10,TOP=20,inf=2147483647;
    int s[N],lis[N];
    ll ans[N];
    int n;
    namespace Sa{/*{{{*/
    	set<int> rec;
    	set<int>::iterator it,pre,nxt;
    	int a[N],b[N],c[N],sa[N],height[N],rk[N];
    	int mn[N][TOP+1];
    	int tot,mx,n;
    	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){
    		n=_n;
    		int cnt=0;
    		mx=0;
    		for (int i=1;i<=n;++i) a[i]=s[i],b[i]=i,mx=max(a[i],mx);
    		sort(n);
    		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(){
    		for (int i=1;i<=n;++i) mn[i][0]=height[i];
    		for (int j=1;j<=TOP;++j)
    			for (int i=n-(1<<j)+1;i>=1;--i)
    				mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
    	}
    	void get_height(){
    		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();
    	}
    	int lcp(int x,int y){//x,y are ranks
    		if (x==y) return n-sa[x]+1;
    		if (x>y) swap(x,y);
    		++x;
    		int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0));
    		return min(mn[x][lg],mn[y-(1<<lg)+1][lg]);
    	}
    	int get_val(int l,int r){
    		if (l>r) swap(l,r);
    		return (n-sa[r]+1)-lcp(l,r);
    	}
    	int calc(){
    		int ret=0;
    		for (int i=1;i<=n;++i)
    			ret+=(n-sa[i]+1)-height[i];
    		return ret;
    	}
    	void print(){
    		set<int>::iterator tmp;
    		for (tmp=rec.begin();tmp!=rec.end(); ++tmp)
    			printf("%d ",*tmp);
    		printf("
    ");
    	}
    	void solve(int n){
    		rec.clear();
    		rec.insert(0); rec.insert(inf); ans[n+1]=0;
    		//print();
    		for (int i=n;i>=1;--i){
    			it=rec.insert(rk[i]).first; pre=it; nxt=it;
    			--pre; ++nxt;
    			ans[i]=ans[i+1];
    			if (*nxt!=inf){
    				ans[i]-=get_val(*pre,*nxt);
    				ans[i]+=get_val(*it,*nxt);
    			}
    			ans[i]+=get_val(*pre,*it);
    			//print();
    		}
    	}
    }/*}}}*/
    void prework(){
    	sort(lis+1,lis+1+n);
    	lis[0]=unique(lis+1,lis+1+n)-lis-1;
    	for (int i=1;i<=n;++i) s[i]=lower_bound(lis+1,lis+1+lis[0],s[i])-lis;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i) scanf("%d",s+i),lis[i]=s[i];
    	prework();
    	reverse(s+1,s+1+n);
    	Sa::get_sa(n);
    	Sa::get_height();
    	Sa::solve(n);
    	for (int i=n;i>=1;--i) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    常用正则表达式
    用Python开始机器学习(2:决策树分类算法)
    Query意图分析:记一次完整的机器学习过程(scikit learn library学习笔记)
    如何成为python高手(转)
    scikit-learn——快速入门
    程序员训练机器学习 SVM算法分享
    应用scikit-learn做文本分类
    sklearn文本特征提取
    中文分词入门之字标注法4
    poj 2965 The Pilots Brothers&#39; refrigerator(dfs 枚举 +打印路径)
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9368642.html
Copyright © 2020-2023  润新知