Loading

GYM-102361J MUV LUV EXTRA kmp求最小循环节

GYM-102361J MUV LUV EXTRA kmp求最小循环节

题意

给定正整数\(a,b\)求最大的\(a \times p - b\times l\),其中\(p\)表示后缀的循环节的总长度,\(l\)表示这个最小循环节的长度

\[1 \leq a,b\leq 1e9\\ 1 \leq |s| \leq 1e7 \]

分析

求这个最大值,不妨枚举\(p\),逆序字符串,这样问题就转化成了求最小循环节。

对于求最小循环节(可以在前面补),可以利用KMP求得next数组,长度为\(n\)的字符串的最小循环节长度就是\(n - next[n]\)

这好像并不显然,不严谨证明如下:

代码

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;

ll rd(){
	ll x = 0;
	int 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;
}

const int maxn = 1e7 + 5;
int Next[maxn];
char s1[maxn],s2[maxn];

int len1,len2;

void getNext(){
	for(int i = 2,j = 0;i <= len2;i++){
		while(s2[i] != s2[j + 1] && j > 0) j = Next[j];
		if(s2[i] == s2[j + 1]) Next[i] = ++j; 
	}
}

int main(){
	ll a,b;
	while(~scanf("%lld%lld",&a,&b)){
		scanf("%s",s1 + 1);
		len1 = 	strlen(s1 + 1);
		int pos = -1;
		for(int i = 1;i <= len1;i++){
			if(s1[i] == '.') {
				pos = i + 1;
				break; 
			} 
		} 
		strcpy(s2 + 1,s1 + pos);
		len2 = strlen(s2 + 1);
		reverse(s2 + 1,s2 + len2 + 1);
		getNext();
		ll ans = a - b;
		for(int i = 1;i <= len2;i++){
			ans = max(ans,a * i - b * (i - Next[i]));
		}
		cout << ans << '\n';	
	}
}
posted @ 2021-03-17 21:53  MQFLLY  阅读(87)  评论(0编辑  收藏  举报