DTOJ #3314. constructive

【题目描述】

有一个空串,每次可以花费 $a$ 的代价在后面添加一个字母,或花费 $b \times \lvert S \rvert$ 的代价将该串复制一遍放到前面。其中 $\lvert S \rvert$ 为当前字符串长度。

现给定一个字符串 $S$,求构造 $S$ 的最小代价。

【输入格式】

第一行一个字符串 $S$。

第二行两个正整数 $a,b$。

【输出格式】

一行一个正整数表示最小代价。

【样例】

样例输入
aab
3 2

样例输出
8

【数据范围与提示】

字符串长度不超过 $10^6$,$a,b \leq 10^5$。

【题解】

显然直接 $dp$ 即可。

$$f_i=min(f_{i-1}+a,[i \ mod \ 2==0][str(1,\frac{i}{2})==str(\frac{i}{2}+1,i)](f_{\frac{i}{2}}+b\times \frac{i}{2}))$$

判断字符串相等可用 $exkmp$ $hash$。

【代码】

#include<bits/stdc++.h>
typedef unsigned long long Hash;
const Hash HASH=13131313;
Hash Pow[1000010],hsh[1000010];
long long f[1000010],a,b;
char S[1000010];
inline Hash check ( int l,int r ) { return hsh[r]-hsh[l-1]*Pow[r-l+1]; }
signed main()
{
    scanf("%s %lld%lld",S+1,&a,&b);
    int n=strlen(S+1);Pow[0]=1;
    for ( int i=1;i<=n;i++ ) Pow[i]=Pow[i-1]*HASH;
    for ( int i=1;i<=n;i++ ) hsh[i]=hsh[i-1]*HASH+S[i];
    for ( int i=1;i<=n;i++ )
    {
        f[i]=f[i-1]+a;
        if ( !(i&1) and check(1,i>>1)==check((i>>1)+1,i) ) f[i]=std::min(f[i],f[i/2]+1LL*b*(i/2));
    }
    return !printf("%lld\n",f[n]);
}

猜你喜欢

转载自www.cnblogs.com/RenSheYu/p/11330239.html
今日推荐