codeforces F.Forbidden Indices后缀数组+LCP

F. Forbidden Indices
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a string s consisting of n lowercase Latin letters. Some indices in this string are marked as forbidden.

You want to find a string a such that the value of |af(a) is maximum possible, where f(a) is the number of occurences of a in s such that these occurences end in non-forbidden indices. So, for example, if s is aaaaa is aa and index 3 is forbidden, then f(a) = 2 because there are three occurences of a in s (starting in indices 12 and 3), but one of them (starting in index 2) ends in a forbidden index.

Calculate the maximum possible value of |af(a) you can get.

Input

The first line contains an integer number n (1 ≤ n ≤ 200000) — the length of s.

The second line contains a string s, consisting of n lowercase Latin letters.

The third line contains a string t, consisting of n characters 0 and 1. If i-th character in t is 1, then i is a forbidden index (otherwise i is not forbidden).

Output

Print the maximum possible value of |af(a).

Examples
input
5
ababa
00100
output
5
input
5
ababa
00000
output
6
input
5
ababa
11111
output
0

题解:

某些位置不可以作为串的结束位置,这样不好做,把这个字符串反序。然后限制条件就变成了有的字符不能作为串的开始。

然后对字符串求后缀数组sa和高度数组height。

然后的话,求|a|*f(a)的值就对应到了height数组里面的最大矩形面积,用单调栈的方法进行处理,但是有限制条件,即矩形块中有的部分是以forbidden为开始的后缀,不能被算进去,所以还要减去这些被限制的后缀串。用前缀sum维护即可在O(1)的时间内减去限制串数目。


代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
struct P{
	int i,w,forbid;
};
int n;
const int maxn = 200007;
int wa[maxn],wb[maxn],wv[maxn],cnt[maxn];
int cmp(int *r , int a, int b, int l,int n)
{
	int a2 = a+l >= n ? -1:r[a+l];
	int b2 = b+l >= n ? -1:r[b+l];
    return r[a] == r[b] && a2 == b2;
}
void da (int *r , int *sa , int n, int m)
{
    int i, j, p, *x = wa, *y = wb , *t;
    for(i = 0; i < m; i++) 
        cnt[i] = 0;
    for(i = 0; i < n; i++) 
        cnt[x[i] = r[i]]++;
    for(i = 1; i < m; i++) 
        cnt[i] += cnt[i-1];
    for(i = n-1; i >= 0; i--) 
        sa[--cnt[x[i]]] = i;
    for(j = 1,p = 1; p < n ; j *= 2,m = p)
    {
        for(p = 0, i = n - j; i < n; i++) 
            y[p++]=i;
        for(i = 0; i < n; i++)
            if(sa[i] >= j)
                y[p++] = sa[i] - j;
        for(i = 0; i < n; i++)
            wv[i] = x[y[i]];
        for(i = 0; i < m; i++)
            cnt[i] = 0;
        for(i = 0; i < n; i++)
            cnt[wv[i]]++;
        for(i = 1; i < m; i++)
            cnt[i] += cnt[i-1];
        for(i = n-1; i >= 0; i--)
            sa[--cnt[wv[i]]] = y[i];
        for(t = x,x = y,y = t,p = 1,x[sa[0]] = 0,i = 1; i < n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j,n)?p-1:p++;
    }
}
int height[maxn],rk[maxn];
void calcheight(int *r,int *sa,int n){
	int i,j,k = 0;
	for(int i = 0;i < n;i++) rk[sa[i]] = i;
	for(i = 0;i < n;height[rk[i++]] = k)
		for(k?k--:0,j = sa[rk[i]?rk[i]-1:0];rk[i]>0 &&i+k<n && j+k<n && r[i+k] == r[j+k];k++);
}
char s[maxn];
int per[maxn];
int sa[maxn];
int r[maxn];
P stk[maxn];
int top;
int sum[maxn];
main(){
	cin>>n;
	char c;
	for(int i = 0;i < n;i++){
		char c;
		scanf(" %c",&c);
		s[n-1-i] = c;
		r[n-1-i] = c - 'a' + 1;
	}
	s[n] = 0;
	int ans = 0; 
	for(int i = 0;i < n;++i){
		char c;
		scanf(" %c",&c);
		per[n-1-i] = c == '1';
	}
	//ans = max(ans,tmp);
	//cout <<ans<<endl;
	for(int i = 0;i < n;++i){
		if(!per[i]) {
			ans = n-i;break;
		}
	}
	da(r,sa,n,30);
	calcheight(r,sa,n);
	height[n] = 0;
	sum[0] = per[sa[0]];
	for(int i = 1;i < n;++i) sum[i] = sum[i-1] + per[sa[i]];
	top = 0;
	for(int i = 1;i <= n;i++){
		if(!top || height[i] > height[stk[top].i]) stk[++top] = (P){i,1,0};
		else{
			int tmp = 0,forbids = 0;
			while(top && height[stk[top].i] >= height[i]){
				tmp += stk[top].w;
				forbids = sum[i-1] - sum[i-1-tmp-1];
				ans = max(ans,(tmp+1-forbids)*height[stk[top].i]);
				--top;
			}
			stk[++top] = (P){i,tmp+1,0};
		}
	}
	cout<<ans<<endl;
	return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值