题目描述
JohnCheng最近沉迷几何,导致走火入魔,于是打算搞下string来缓解压力。他有一张草稿纸,最开始什么都没有(可以视为有一个空串)。每一步他可以花费 aaa 时间在当前字符串后面加入任意一个字符,也可以花费 b×∣S∣b \times |S|b×∣S∣ (S为当前字符串)的时间把S抄一遍放在S前面。
旁边的Worldwide_D正苦于一道字符串毒瘤题,他获得了一个数据点,数据点里有一个长度不大于 10610^6106 的字符串。他把字符串发给JohnCheng,问他至少能在多长时间内构造出这个字符串。
JohnCheng:水题一道。然后开始睡觉,并把问题交给了你。
数据范围
∣S∣≤106,1≤b<a≤105∣S∣≤10 ^6 ,1≤b<a≤10 ^5∣S∣≤106,1≤b<a≤105
题解
考虑 dpdpdp , fif_ifi 表示构造好了前 iii 个字符的最小代价,则首先 fi=fi−1+af_i=f_{i-1}+afi=fi−1+a
然后如果 iii 是偶数并且 [1.i2][1.\frac{i}{2}][1.2i] 和 [i2+1,i][\frac{i}{2}+1,i][2i+1,i] 的字符串相同的话,则有 fi=min(fi,fi2+b×i2)f_i=min(f_i,f_{\frac{i}{2}}+b \times \frac{i}{2})fi=min(fi,f2i+b×2i) ,判断相同就用哈希判断
效率: O(∣S∣)O(|S|)O(∣S∣)
代码
#include <bits/stdc++.h>
#define LL long long
#define U unsigned LL
using namespace std;
const int N=1e6+5;
const U K=793999;
int a,b,n;char s[N];
LL f[N];U h[N],k[N];
U H(int l,int r){
return h[r]-h[l-1]*k[r-l+1];
}
int main(){
scanf("%s%d%d",s+1,&a,&b);
n=strlen(s+1);k[0]=1;
for (int i=1;i<=n;i++)
k[i]=k[i-1]*K,h[i]=h[i-1]*K+s[i];
for (int i=1;i<=n;i++){
f[i]=f[i-1]+a;
if (!(i&1) && H(1,i>>1)==H((i>>1)+1,i))
f[i]=min(f[i>>1]+1ll*b*(i>>1),f[i]);
}
return printf("%lld\n",f[n]),0;
}