标签:lld can return style hash 格式 text $1 pre
【题目描述】
有一个空串,每次可以花费 $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]); }
标签:lld can return style hash 格式 text $1 pre
原文地址:https://www.cnblogs.com/RenSheYu/p/11330239.html