zoukankan      html  css  js  c++  java
  • [NOI 2016] 优秀的拆分

    题目传送-Luogu4117

    题意:

    (T)组数据,对于每组数据:
    给你一个长度为(n)的字符串(S)
    定义一个字符串(t)是好的,当且仅当它能被表示成(aabb)的形式,其中a和b都是字符串(可以相同)
    (S)中有多少个子串是好的(本质相同位置不同也算不同)
    (T le 10,n le 30000)

    题解:

    这题的构造方法极其巧妙,是道好题。
    我们可以维护两个数组分别表示某个位置为结尾/开头的aa型字符串有多少个
    那显然(ans=sum_{i=1}^{n-1}f_{i}*g_{i+1})(大概意思一下)
    那考虑如何统计(f)(g)
    我们枚举(a)的长度(len),并设置(len,2*len,...,lfloor frac{n}{len} floor *len)为关键点,求出相邻关键点的(LCP)(LCS)(最长公共前/后缀),大概画幅图就知道对那些点有贡献,差分一下就可以得到(f)(g)了。

    过程:

    犯了个严重错误:见我的错题集LCA中的第1点
    同时写代码的时候在变量代表的意义上纠结不清导致调题过程过长

    代码:

    const int N=30010;
    int n;
    char S[N];
    int valf[N],valb[N];//i as end/start
    int s_t[2][N<<2],t_s[2][N<<1],dep[2][N<<1],fa[2][N<<1],cur=0;
    int head[N<<1],nxt[N<<1],to[N<<1],lst=0;
    int NOW,ref[2][N];
    inline void adde(int x,int y) {
    	nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;
    }
    namespace SAM {
    	const int U=26;
    	struct NODE {
    		int tranc[U],dep,fa;
    	}tre[N<<1];
    	int las,rt,ind;
    	inline int New_Node() {
    		++ind; mem(tre[ind].tranc,0); tre[ind].dep=tre[ind].fa=0;
    		return ind;
    	}
    	inline void Init() {
    		mem(tre,0);
    		cur=lst=0; mem(head,0);
    		ind=0; las=rt=New_Node();
    	}
    	inline void Insert(int x) {
    		// printf("test:%d
    ",tre[1].tranc[1]);
    		int p=las,np=New_Node(); tre[np].dep=tre[p].dep+1;
    		for(;p && !tre[p].tranc[x];p=tre[p].fa) tre[p].tranc[x]=np;
    		if(!p) {tre[np].fa=rt;}
    		else {
    			int q=tre[p].tranc[x];
    			if(tre[p].dep+1==tre[q].dep) {tre[np].fa=q;}
    			else {
    				int nq=New_Node(); tre[nq].dep=tre[p].dep+1;
    				memcpy(tre[nq].tranc,tre[q].tranc,sizeof(tre[q].tranc));
    				tre[nq].fa=tre[q].fa; tre[q].fa=tre[np].fa=nq;
    				for(;p && tre[p].tranc[x]==q;p=tre[p].fa) tre[p].tranc[x]=nq;
    			}
    		}
    		las=np;
    	}
    	inline void Build() {
    		for(int i=1;i<=ind;i++)
    			if(tre[i].fa) adde(tre[i].fa,i);
    	}
    	void dfs(int u) {
    		// printf("u=%d dep=%d
    ",u,tre[u].dep);
    		dep[NOW][u]=tre[u].dep; fa[NOW][u]=tre[u].fa;
    		s_t[NOW][++cur]=u; t_s[NOW][u]=cur;
    		for(int i=head[u];i;i=nxt[i]) {
    			int v=to[i];
    			if(v) {
    				dfs(v);
    				s_t[NOW][++cur]=u;
    			}
    		}
    	}
    }
    inline void Get_SAM(char *s) {
    	if(NOW) reverse(s+1,s+n+1);
    	for(int i=1;i<=n;i++) {
    		SAM::Insert(s[i]-'a');
    		ref[NOW][NOW ? n-i+1 : i]=SAM::las;
    	}
    	SAM::Build(); SAM::dfs(SAM::rt);
    }
    namespace ST {
    	const int lgN=18;
    	int st[2][N<<2][lgN+3],lg[N<<2];
    	inline void Set() {
    		lg[1]=0;
    		for(int i=2;i<=120000;i++)
    			lg[i]=lg[i>>1]+1;
    	}
    	inline void Init() {
    		mem(st,63);
    	}
    	inline int Comp(int x,int y,int c) {return dep[c][x]<dep[c][y] ? x : y;}
    	inline void Get_ST() {
    		// printf("???:%d %d
    ",cur,SAM::ind*2-1);
    		assert(cur==SAM::ind*2-1);
    		// for(int i=1;i<=SAM::ind*2-1;i++) printf("%d ",s_t[NOW][i]); puts("");
    		for(int i=1;i<=SAM::ind*2-1;i++) st[NOW][i][0]=s_t[NOW][i];
    		// printf("%d
    ",tot);
    		for(int j=1;j<=lgN;j++)
    			for(int i=1;i+(1<<j)-1<=SAM::ind*2-1;i++) {
    				st[NOW][i][j]=Comp(st[NOW][i][j-1],st[NOW][i+(1<<(j-1))][j-1],NOW);
    				// printf("%d %d %d:%d
    ",c,i,j,st[c][i][j]);
    			}
    		// printf("st[1][8][1]=%d
    ",st[1][8][1]);
    	}
    	inline int Query(int c,int x,int y) {
    		// printf("%d %d %d %d %d dep[2]=%d
    ",c,x,y,ref[c][x],ref[c][y],dep[1][2]);
    		x=t_s[c][ref[c][x]],y=t_s[c][ref[c][y]];
    		if(x>y) swap(x,y);
    		// if(x>y) swap(x,y);
    		int tmp=lg[y-x+1];
    		// printf("%d %d %d
    ",x,y,tmp);
    		// printf("ask::%d
    ",fa[c][Comp(st[c][x][tmp],st[c][y-(1<<tmp)+1][tmp])]);
    		return dep[c][Comp(st[c][x][tmp],st[c][y-(1<<tmp)+1][tmp],c)];
    	}
    }
    inline void Init() {
    	// puts("?");
    	mem(dep,0);
    	SAM::Init(); ST::Init();
    	mem(valf,0); mem(valb,0);
    }
    inline void Work() {
    
    	Init();
    	NOW=0; Get_SAM(S); ST::Get_ST(); SAM::Init();
    	NOW=1; Get_SAM(S); ST::Get_ST(); SAM::Init();
    	// printf("1 2 :%d
    ",ST::Query(1,1,2));
    	for(int len=1;len<=n;len++) {
    		for(int st=1;st+len<=n;st+=len) {
    			int lcp=ST::Query(1,st,st+len),lcs=ST::Query(0,st,st+len);
    			// printf("%d %d lcp=%d lcs=%d
    ",st,st+len,lcp,lcs);
    			if(lcp+lcs-2>=len-1) {
    				int s=max(st,st+len-lcs),t=min(st+len-1,st+lcp-1);//s=st+len-1-lcs+1
    				// printf("%d %d
    ",s,t);
    				// printf("%d %d %d
    ",len,s+len,t+len+1);
    				++valf[s+len]; --valf[t+len+1];
    				// printf("%d %d %d
    ",len,s-len,t-len+1);
    				++valb[s-len+1]; --valb[t-len+2];
    			}
    		}
    	}
    	for(int i=1;i<=n;i++)
    		valf[i]+=valf[i-1];
    	for(int i=1;i<=n;i++)
    		valb[i]+=valb[i-1];
    	ll ans=0;
    	for(int i=2;i<n-1;i++)
    		ans+=1ll*valf[i]*valb[i+1];
    	printf("%lld
    ",ans);
    }
    signed main() {
    	ST::Set();
    	int T; read(T);
    	while(T--) {
    		scanf("%s",S+1); n=strlen(S+1);
    		Work();
    	}
    	return 0;
    }
    

    用时:3h

  • 相关阅读:
    javaweb消息中间件——rabbitmq入门
    virtual box 桥接模式(bridge adapter)下无法获取ip(determine ip failed)的解决方法
    Apache Kylin本地启动
    git操作
    Java学习总结
    Java中同步的几种实现方式
    hibernate exception nested transactions not supported 解决方法
    vue 中解决移动端使用 js sdk 在ios 上一直报invalid signature 的问题解决
    cookie 的使用
    vue 专门为了解决修改微信标题而生的项目
  • 原文地址:https://www.cnblogs.com/functionendless/p/9562710.html
Copyright © 2011-2022 走看看