题解 优美的旋律
并不会做
- 关于一个字符串的最小循环节:即为 \(len_s-max\{len_{boader}\}\),
读者自证不难
于是就很好写了
对于每个子区间,令区间长为 \(n\),最小循环节长度为 \(len\)
则最小循环节可能出现的次数是 \(\frac{n}{len}\) 的因子
于是不难证明复杂度是 \(O(n^2logn)\) 的
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3010
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define int long long
int n, a, b;
char s[N];
namespace force{
int nxt[N], ans;
ull p[N], h[N];
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
int calc(int l, int r) {
int len=r-l+1, ans=0;
for (int i=1; i<=len/2; ++i) if (len%i==0) {
ull t=hashing(l, l+i-1);
for (int j=l+i; j<=r; j+=i) if (hashing(j, j+i-1)!=t) goto jump;
ans=max(ans, a*i+b*(len/i));
jump: ;
}
return ans;
}
void solve() {
p[0]=1;
for (int i=1; i<=n; ++i) p[i]=p[i-1]*base;
for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
for (int i=1; i<=n; ++i) for (int j=i; j<=n; ++j) ans=max(ans, calc(i, j));
printf("%d\n", ans);
exit(0);
}
}
namespace task{
vector<int> div[N];
int nxt[N], ans;
void calc(char* s, int n) {
nxt[1]=0;
for (int i=2,j=0; i<=n; ++i) {
while (j && s[i]!=s[j+1]) j=nxt[j];
if (s[i]==s[j+1]) ++j;
nxt[i]=j;
}
for (int i=1; i<=n; ++i) {
int len=i-nxt[i];
if (i%len) continue;
for (auto j:div[i/len]) ans=max(ans, a*len*j+b*(i/len/j));
}
}
void solve() {
for (int i=1; i<=n; ++i)
for (int j=2; i*j<N; ++j)
div[i*j].pb(i);
for (int i=1; i<=n; ++i) calc(s+i-1, n-i+1);
printf("%d\n", ans);
exit(0);
}
}
signed main()
{
freopen("melody.in", "r", stdin);
freopen("melody.out", "w", stdout);
scanf("%d%d%s", &a, &b, s+1);
n=strlen(s+1);
// force::solve();
task::solve();
return 0;
}