#3314. constructive

题目描述

JohnCheng最近沉迷几何,导致走火入魔,于是打算搞下string来缓解压力。他有一张草稿纸,最开始什么都没有(可以视为有一个空串)。每一步他可以花费 $a$ 时间在当前字符串后面加入任意一个字符,也可以花费 $b \times |S|$ (S为当前字符串)的时间把S抄一遍放在S前面。

旁边的Worldwide_D正苦于一道字符串毒瘤题,他获得了一个数据点,数据点里有一个长度不大于 $10^6$ 的字符串。他把字符串发给JohnCheng,问他至少能在多长时间内构造出这个字符串。

JohnCheng:水题一道。然后开始睡觉,并把问题交给了你。

数据范围

$∣S∣≤10 ^6 ,1≤b<a≤10 ^5$

题解

考虑 $dp$ , $f_i$ 表示构造好了前 $i$ 个字符的最小代价,则首先 $f_i=f_{i-1}+a$

然后如果 $i$ 是偶数并且 $[1.\frac{i}{2}]$ 和 $[\frac{i}{2}+1,i]$ 的字符串相同的话,则有 $f_i=min(f_i,f_{\frac{i}{2}}+b \times \frac{i}{2})$ ,判断相同就用哈希判断

效率: $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;
}

 

posted @ 2019-08-09 14:28  xjqxjq  阅读(169)  评论(0编辑  收藏  举报