【题解】Codeforces873F. Forbidden Indices 后缀自动机

给定一个长为 n ( 2 e 5 ) n(2e5) 的字符串 s s ,一些位置被标记为不可用。

找到一个子串, 长度*合法出现次数 最大,合法出现次数是指endpos不在不可用位置上的出现次数。

求最大的 长度*合法出现次数


令不合法的位置不产生cnt的贡献即可,SAM模板掌握题,既然写题意了就发出来吧。


/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 200016, MOD = 1000000007;

int sz, lst; //后缀自动机大小,上一次插入的节点
int ch[M<<1][26], len[M<<1], link[M<<1], cnt[M<<1];

void extend(const char *s, const char *ban)
{
	for(int i=0; s[i]; ++i)
	{
		int c = s[i]-'a';
		int cur = ++sz;
		len[cur] = len[lst] + 1;

		int p = lst;
		while(!ch[p][c])
		{
			ch[p][c] = cur;
			p = link[p];
		}
		if(ch[p][c] != cur)
		{
			int q = ch[p][c];
			if(len[p] + 1 == len[q]) link[cur] = q;
			else
			{
				int clone = ++sz;
				memcpy(ch[clone], ch[q], sizeof(ch[q]));
				link[clone] = link[q];
				len[clone] = len[p]+1;
				while(ch[p][c]==q)
				{
					ch[p][c] = clone;
					p = link[p];
				}
				link[q] = link[cur] = clone;
			}
		}
		lst = cur;
		cnt[cur] += (ban[i]=='0');
	}
	vector<int> nodes;
	for(int i=1; i<=sz; ++i)
		nodes.push_back(i);
	sort(nodes.begin(), nodes.end(), [&](int a, int b){
		return len[a]>len[b];
	});
	for(auto u:nodes)
		cnt[link[u]] += cnt[u];
}

char str[M], ban[M];
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	read();
	scanf("%s %s", str, ban);
	extend(str, ban);

	ll ans = 0;
	for(int i=1; i<=sz; ++i)
	{
		ans = max(ans, 1ll*cnt[i]*len[i]);
	}
	cout << ans << "\n";

    return 0;
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
发布了375 篇原创文章 · 获赞 305 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/103191712