zoukankan      html  css  js  c++  java
  • JSOI2013 快乐的JYY(manacher,回文串)

    萌新不会PAM
    于是用manacher+hash
    O(nlogn)过了这题
    首先我们有一个结论
    对于一个长度n的串,它的本质不同的回文子串数量是O(n)的

    然后我们先用manacher算出半径r[i]
    然后开一个数组记录一下最长回文子串在原字符串中哪个位置

    我们考虑任意一个>=3的回文子串不论是奇是偶,去掉头尾它依然是回文串
    又因为只有O(n)个本质不同的回文子串(以下简称子串),所以我们可以考虑用字符串哈希map给每个本质不同的子串标号,然后每个子串的节点把去掉头尾的子串的节点当作父亲,就类似于AC自动机的fail树,意即你访问子节点的串同时一定遍历了父节点的串,然后只有长度为1或2的子串向根连边(把根当作父亲).
    于是这就形成了一颗树

    于是我们每遍历一个以某个位置为对称轴(可以是字母也可以是两个字母间的空隙)的最长回文子串就给它打个标记,一个回文子串遍历了多少次显然是它树上的结点的子树和,于是我们可以算出每个回文子串在A中出现了几次,同理对B建树,然后把相同的子串在两树中的方案乘起来再累加到ans里,就做完了

    /*快乐的JYY*/
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstring>
    #include<map>
    using namespace std;
    #define ll long long
    const int maxn = 2e5 + 10; 
    #define ul unsigned long long
    ul mi[maxn];
    ll ans = 0;
    int head[maxn];
    int idcnt = 0;
    struct Edge{
    	int nxt,point;
    }edge[maxn*2];
    int tot;
    void add(int x,int y){
    	edge[++tot].nxt = head[x];
    	edge[tot].point = y;
    	head[x] = tot;
    }
    struct Str{
    	char str[maxn];	char s[maxn*2];
    	int r[maxn] ;int bit[maxn];ul hash[maxn];map<ul,int>id;
    	ul v[maxn];
    	ll dp[maxn * 2];
    	map<ul,ll>f;
    	int len;
    	int cnt;
    	int rt;
    	#define p 133331
    	void init(){
    		for(int i = 1; i <= len; ++i)
    			hash[i] = hash[i-1] * p + str[i] - 'A' + 1;
    	}
    	ul calc(int l,int r){
    		int k = r - l + 1;
    		return hash[r] - mi[k] * hash[l-1];
    	}
    	void manacher(){
    		s[++cnt] = '~',s[++cnt] = '#';
    		for(int i = 1; i <= len; ++i){
    			s[++cnt] = str[i];	s[++cnt] = '#';
    			bit[cnt] = i;
    		}
    		s[++cnt] = '!';
    		s[cnt+1] = '';
    		int mr = 0,mid = 0;
    		for(int i = 2; i <= cnt - 1; ++i){
    			if(i <= mr)		r[i] = min(r[(mid<<1)-i],mr - i + 1);
    			else	r[i] = 1;
    			while(s[i+r[i]] == s[i-r[i]])		r[i]++;
    			if(i + r[i] > mr){
    				mr = i + r[i] - 1;
    				mid = i;
    			}
    		} 
    	}
    	void build(){
    		rt = ++idcnt;
    		for(int i = 2; i <= cnt - 1; ++i){
    			int L = i - r[i] + 1,R = i + r[i] - 1;
    			if(L == R && s[L] == '#')	continue;
    			L = bit[L] + 1,R = bit[R];
    			int lst = 0;
    			while(L <= R){	
    				ul val = calc(L,R);
    				if(id.find(val) == id.end()){
    					id[val] = ++idcnt;
    					v[idcnt] = val;
    					if(lst)		add(id[val],lst);
    				}
    				else{
    					if(lst)		add(id[val],lst);
    					break;
    				}
    				lst = id[val];
    				if(L == R){
    					add(rt,id[val]);
    				} 
    				if(R == L + 1){
    					add(rt,id[val]);
    				}
    				L++,R--;
    			}
    			L = i - r[i] + 1,R = i + r[i] - 1;
    			L = bit[L] + 1,R = bit[R];
    			ul val = calc(L,R);
    			dp[id[val]]++;
    		}
    	}
    	void dfs(int x){
    		for(int i = head[x]; i ; i = edge[i].nxt){
    			int y = edge[i].point;
    			dfs(y);
    			dp[x] += dp[y];
    		}
    		f[v[x]] += dp[x];
    	}
    }A,B;
    void init(){
    	mi[0] = 1;
    	for(int i = 1; i <= 1e5; ++i)
    		mi[i] = mi[i-1] * p;
    	scanf("%s",A.str+1);
    	A.len = strlen(A.str + 1);
    	A.init();
    	A.manacher();
    	A.build();
    	A.dfs(A.rt);
    	scanf("%s",B.str+1);
    	B.len = strlen(B.str + 1);
    	B.init();
    	B.manacher();
    	B.build();
    	B.dfs(B.rt);
    }
    void solve(int x){
    	if(x != A.rt){
    		ans += A.f[A.v[x]] * B.f[A.v[x]];
    	}
    	for(int i = head[x]; i ; i = edge[i].nxt){
    		int y = edge[i].point;
    		solve(y);
    	}
    }
    int main()
    {
    	init();
    	solve(A.rt);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    工作笔记之20170223:①关于Html5的placeholder属性,②以及input的outline:none的样式问题
    工作笔记之:如何在eclipse安装CVS插件?找了很久的,自己总结一下
    ajax后台请求两种方法(js和jQuery)
    22
    21
    20
    19
    18
    17
    16
  • 原文地址:https://www.cnblogs.com/y-dove/p/13492985.html
Copyright © 2011-2022 走看看