zoukankan      html  css  js  c++  java
  • loj #6070. 「2017 山东一轮集训 Day4」基因

    回文自动机好题啊!

    解法一

    每$sqrt n (分一块 每块建回文自动机到字符串末尾。 顺便开三个)sqrt n * n(的数组记下预处理答案,回文自动机头指针,和每个节点第一次出现的右端点 询问的时候回文自动机前端添加,算出答案。 貌似不能写均摊复杂度的回文自动机,只能写单次复杂度有证明的。 设)T(为字符集大小 时间复杂度)O(Tn+n sqrt n)$

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100010,D=320;
    int pre[D][N],preworkans[D][N],firstappear[D][N],vis[N];
    struct pam{
    	struct pamnode{
    		int len,fa,anc[26],trans[26];
    	}T[N];
    	int tot,fi,la;
    	pam(){
    		T[1].len=-1;
    		T[0].fa=1;
    		for (int j=0; j<26; ++j) T[0].anc[j]=1;
    		tot=1;
    		fi=0;
    		la=0;
    	}
    	void pushback(char *s,int l,int r){
    		int c=s[r]-'a';
    		if (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].anc[c];
    		if (!T[la].trans[c]){
    			int q=++tot,k=T[la].fa;
    			T[q].len=T[la].len+2;
    			if (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) T[q].fa=T[T[k].anc[c]].trans[c];
    			else T[q].fa=T[k].trans[c];
    			memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
    			T[q].anc[s[r-T[T[q].fa].len]-'a']=T[q].fa;
    			T[la].trans[c]=q;
    		}
    		la=T[la].trans[c];
    		if (T[la].len==r-l+1) fi=la;
    	}
    	void pushfront(char *s,int l,int r){
    		int c=s[l]-'a';
    		if (l+T[fi].len+1>r||s[l]!=s[l+T[fi].len+1]) fi=T[fi].anc[c];
    		if (!T[fi].trans[c]){
    			int q=++tot,k=T[fi].fa;
    			T[q].len=T[fi].len+2;
    			if (l+T[k].len+1>r||s[l]!=s[l+T[k].len+1]) T[q].fa=T[T[k].anc[c]].trans[c];
    			else T[q].fa=T[k].trans[c];
    			memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
    			T[q].anc[s[l+T[T[q].fa].len]-'a']=T[q].fa;
    			T[fi].trans[c]=q;
    		}
    		fi=T[fi].trans[c];
    		if (T[fi].len==r-l+1) la=fi;
    	}
    }A;
    int ty,n,q,S,clk,ans;
    char s[N];
    int main(){
    	scanf("%d%d%d%s",&ty,&n,&q,s+1);
    	S=sqrt(n);
    	for (int i=0; i*S+1<=n; ++i){
    		A.fi=A.la=0; ++clk;
    		for (int j=i*S+1; j<=n; ++j){
    			A.pushback(s,i*S+1,j);
    			preworkans[i][j]=preworkans[i][j-1];
    			if (vis[A.la]<clk){
    				vis[A.la]=clk;
    				firstappear[i][A.la]=j;
    				++preworkans[i][j];
    			}
    			pre[i][j]=A.fi;
    		}
    	}
    	while (q--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		l^=(ty*ans);
    		r^=(ty*ans);
    		++clk;
    		if ((l-1)/S==(r-1)/S){
    			A.fi=A.la=0;
    			ans=0;
    			for (int i=l; i<=r; ++i){
    				A.pushback(s,l,i);
    				if (vis[A.la]<clk){
    					vis[A.la]=clk;
    					++ans;
    				}
    			}
    		}
    		else{
    			int L=(l-1)/S+1-(l%S==1);
    			A.fi=pre[L][r];
    			ans=preworkans[L][r];
    			for (int i=L*S; i>=l; --i){
    				A.pushfront(s,i,r);
    				if (vis[A.fi]<clk){
    					vis[A.fi]=clk;
    					if (firstappear[L][A.fi]>r||firstappear[L][A.fi]==0) ++ans;
    				}
    			}
    		}
    		cout<<ans<<'
    ';
    	}
    }
    

    解法2

    记回文自动机上一个节点的串长为(len(x)),父节点为(fa(x)),则对于回文树上一条链,从叶子到根,(len(x)-len(fa(x)))递减,且只有(log)种取值,也就是说,可以分成(log)个等差数列。
    主席树维护扫描右端点时左端点的答案,一个等差数列就是一个区间加。
    时间复杂度(O(nlog^2(n)))

    #include <bits/stdc++.h>
    using namespace std;
    #define debug(x) cerr<<#x<<":"<<x<<endl
    const int N=100010;
    const int P=270010;
    const int D=17*17*N;
    struct zkw{
    	int u,st[P];
    	void init(int len){
    		for (u=1; u<len; u<<=1); 
    		--u;
    	}
    	void mark(int s,int t){
    		//cerr<<"Mark"<<s<<" "<<t<<endl;
    		for (s+=u; s; s>>=1) st[s]=max(st[s],t);
    	}
    	int ask(int s,int t){
    		//cerr<<"ask"<<s<<" "<<t<<endl;
    		int ret=0;
    		for (s+=u-1,t+=u+1; s^t^1; s>>=1,t>>=1){
    			if (~s&1) ret=max(ret,st[s^1]);
    			if (t&1) ret=max(ret,st[t^1]);
    		}
    		//debug(ret);
    		return ret;
    	}
    }seg1;
    struct president{
    	int ll,rr,tot;
    	struct presidentnode{
    		int l,r,v;
    	}T[D];
    	void add(int &ind,int l,int r){
    		/*if (l!=13||r!=12){
    		debug(l); debug(r); debug(tot);
    		debug(ll); debug(rr);
    		}*/	
    		T[++tot]=T[ind];
    		ind=tot;
    		//cerr<<"CC"<<endl;
    		if (ll<=l&&r<=rr) return void(++T[ind].v);
    		int mid=(l+r)>>1;
    		if (ll<=mid) add(T[ind].l,l,mid);
    		if (mid<rr) add(T[ind].r,mid+1,r);
    	}
    	int ask(int ind,int l,int r){
    		if (l==r) return T[ind].v;
    		int mid=(l+r)>>1;
    		return (ll<=mid?ask(T[ind].l,l,mid):ask(T[ind].r,mid+1,r))+T[ind].v;
    	}
    }seg2;
    struct pam{
    	vector<int> g[N];
    	struct pamnode{
    		int fa,len,d,df,trans[26];
    	}T[N];
    	int la,tot,dfn[N],clk,lst[N];
    	pam(){
    		T[1].len=-1;
    		T[0].fa=1;
    		T[0].d=-1;
    		tot=1;
    		la=0;
    	}
    	int pushback(char *s,int l,int r){
    		int c=s[r]-'a';
    		while (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].fa;
    		if (!T[la].trans[c]){
    			int q=++tot,k=T[la].fa;
    			T[q].len=T[la].len+2;
    			while (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) k=T[k].fa;
    			T[q].fa=T[k].trans[c];
    			T[la].trans[c]=q;
    			T[q].d=(T[q].fa?T[q].len-T[T[q].fa].len:0);
    			T[q].df=(T[q].d==T[T[q].fa].d?T[T[q].fa].df:q);
    		}
    		return la=T[la].trans[c];
    	}
    	void dfs(int x){
    		//debug(x); debug(fa);
    		dfn[x]=clk++;
    		for (auto i:g[x]) dfs(i);
    		lst[x]=clk-1;
    	}
    	void prework(){
    		for (int i=tot; i>1; --i) g[T[i].fa].push_back(i);
    		dfs(0);
    	}
    }A;
    int ty,n,q,ans,rt[N],rec[N];
    char s[N];
    void build(){
    	//for (int i=1; i<=A.tot; ++i) debug(A.dfn[i]);
    	seg1.init(A.tot);
    	for (int i=1; i<=n; ++i){
    		rt[i]=rt[i-1];
    		int x=rec[i];
    		while (x>1){
    			seg2.ll=max(seg1.ask(A.dfn[x],A.lst[x])-A.T[x].len+2,1);
    			seg2.rr=i-A.T[A.T[x].df].len+1;
    			//cerr<<"plus"<<i<<" "<<seg2.ll<<" "<<seg2.rr<<" "<<A.T[x].df<<" "<<A.T[x].len<<endl;
    			seg2.add(rt[i],1,n);
    			x=A.T[A.T[x].df].fa;
    		}
    		seg1.mark(A.dfn[rec[i]],i);
    	}
    }
    int main(){
    	scanf("%d%d%d%s",&ty,&n,&q,s+1);
    	for (int i=1; i<=n; ++i) rec[i]=A.pushback(s,1,i)/*,debug(rec[i]),debug(A.T[rec[i]].fa)*/;
    	A.prework();
    	build();
    	while (q--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		l^=(ty*ans);
    		r^=(ty*ans);
    		seg2.ll=l;
    		cout<<(ans=seg2.ask(rt[r],1,n))<<'
    ';
    	}
    }
    
  • 相关阅读:
    汉英单词对照,汉英部分
    解密SQL Server存储过程等对象
    统计信息对执行计划的影响(二)
    统计信息对执行计划的影响(一)
    asp.net 避免 ajax 定时调用,利用 ashx 实现 long polling (长轮询)
    [ADO.NET][Command]如何抓取第一筆資料的第一個欄位或scalar值?
    鱼骨图
    js 中跳出多层循环
    IIS无法 添加/编辑 应用程序扩展名映射的原因
    如何让域名后面不显示xxx.do后缀
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/10073798.html
Copyright © 2011-2022 走看看