• 题解 [NOI2016] 优秀的拆分


    题目传送门

    Description

    给出一个长度为 (n) 的字符串,问有多少个子串,满足可以写成 (AABB) 的形式。

    (nle 3 imes 10^4)

    Solution

    md,直接 hash 暴力就能获得 (95) 分的好成绩。

    考虑正解,我们设 (a_i) 表示以 (i) 结尾能写成 (AA) 形式的后缀个数,(b_i) 表示以 (i) 开头能写成 (AA) 形式的前缀个数。

    我们考虑计算出长度为 (2k) 的字符串产生的贡献。我们每 (k) 个就设置一个端点,那么可以想到的是一个合法的字符串一定会经过且只经过两个相邻端点。

    所以我们对于两个相邻端点考虑,如果两者的前缀的最长公共后缀 lcs 和两者的后缀的最长公共前缀 lcp 满足 (lcs+lcp-1ge k) 那么显然 (i-lcs+1sim i-lcs+1+lcs+lcp-1-k) 都是可以作为开头的点,那么就可以区间增加这一段的 (b)(a) 数组同理。

    求 lcs 和 lcp 直接 SA 就好了。时间复杂度 (Theta(nlog n+nln n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 30005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    char s[MAXN];
    
    struct SA{
    	int n,m,num,x[MAXN],y[MAXN],c[MAXN],sa[MAXN],rk[MAXN],st[MAXN][21];
    	void clear(){
    		memset (x,0,sizeof (x));
    		memset (y,0,sizeof (y));
    	}
    	int query (int l,int r){
    		if (l == r) return n - sa[l] + 1;
    		if (l > r) swap (l,r);++ l;
    		int k = log2 (r - l + 1);
    		return min (st[l][k],st[r - (1 << k) + 1][k]);
    	} 
    	void Build (){
    		n = strlen (s + 1);
    		m = 26;for (Int i = 1;i <= m;++ i) c[i] = 0;
    		for (Int i = 1;i <= n;++ i) x[i] = s[i] - 'a' + 1,c[x[i]] ++;
    		for (Int i = 1;i <= m;++ i) c[i] += c[i - 1];
    		for (Int i = 1;i <= n;++ i) sa[c[x[i]] --] = i;
    		for (Int k = 1;k <= n;k <<= 1){
    			num = 0;for (Int i = n - k + 1;i <= n;++ i) y[++ num] = i;
    			for (Int i = 1;i <= n;++ i) if (sa[i] > k) y[++ num] = sa[i] - k;
    			for (Int i = 1;i <= m;++ i) c[i] = 0;for (Int i = 1;i <= n;++ i) c[x[i]] ++;for (Int i = 1;i <= m;++ i) c[i] += c[i - 1];
    			for (Int i = n;i >= 1;-- i) sa[c[x[y[i]]] --] = y[i],y[i] = 0;swap (x,y),x[sa[1]] = num = 1;
    			for (Int i = 2;i <= n;++ i) num += !(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]),x[sa[i]] = num;
    			m = num;if (m == n) break; 
    		}
    		for (Int i = 1;i <= n;++ i) rk[sa[i]] = i;
    		for (Int i = 1,k = 0;i <= n;++ i){
    			if (rk[i] == 1) k = 0;
    			else{
    				if (k) -- k;
    				int j = sa[rk[i] - 1];
    				while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) ++ k;
    			}
    			st[rk[i]][0] = k; 
    		}
    		for (Int j = 1;(1 << j) <= n;++ j) for (Int i = 1;i + (1 << j) - 1 <= n;++ i) st[i][j] = min (st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    	}
    	int fuckit (int a,int b){return query (rk[a],rk[b]);}
    }S,T;
    
    int n,a[MAXN],b[MAXN];
    
    void Work (){
    	S.clear(),T.clear();
    	scanf ("%s",s + 1),n = strlen (s + 1);
    	S.Build(),reverse (s + 1,s + n + 1),T.Build();
    	memset (a,0,sizeof (a)),memset (b,0,sizeof (b));
    	for (Int len = 1;(len << 1) <= n;++ len)
    		for (Int i = len;i + len <= n;i += len){
    			int l = i,r = i + len,L = n - (r - 1) + 1,R = n - (l - 1) + 1;
    			int lcs = T.fuckit (L,R),lcp = S.fuckit (l,r);
    			lcp = min (lcp,len),lcs = min (lcs,len - 1);
    			if (lcs + lcp >= len){
    				b[i - lcs] ++,b[i - lcs + (lcp + lcs - len + 1)] --;
    				a[r + lcp - (lcp + lcs - len + 1)] ++,a[r + lcp] --;
    			}
    		}
    	for (Int i = 1;i <= n;++ i) a[i] += a[i - 1],b[i] += b[i - 1];
    	long long ans = 0;for (Int i = 1;i < n;++ i) ans += 1ll * a[i] * b[i + 1];
    	write (ans),putchar ('
    ');
    }
    
    signed main(){
    //	freopen ("P1117_6.in","r",stdin);
    	int T;read (T);
    	while (T --> 0) Work ();
     	return 0;
    }
    
  • 相关阅读:
    浅谈移动前端的最佳实践(转)
    程序员的个人发展注意事项(转)
    SQL Server 维护计划实现数据库备份(Step by Step)
    每日一SQL-善用DATEADD和DATEDIFF
    Entity Framework Code First (一)Conventions
    臣服不代表解放你的手
    写在那个毕业五年的日子(转)
    测试驱动开发实践
    领域驱动设计实践上篇(转)
    WebAPI使用多个xml文件生成帮助文档(转)
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14443979.html
Copyright © 2020-2023  润新知