题解:U633098 请输入文本
暴力
随便怎么做都可以,不具体阐述。
朴素 DP
设
其中
直接做这个 DP 是
非正解 DP 优化
考虑到字符串,直接使用 hash 可以优化到
周期性
当你就差临门一脚时,不妨静下心来,回过头再看一看题。“周期性”,这是题目的唯一一个特殊性质,可以作为我们的突破口。
如果
KMP 优化 DP
回看转移中的
注:这里的“周期”指的是可以由某个子串重复多次并取其子串构成,即“不完全周期”。
补充
- 这道题有求出“周期”的方法,可供参考。
- 感谢 @gaozeju 提供的思路:这道题有直接求出最佳转移点的方法,大概就是暴力跳 kmp 的优化,可以直接套用。
参考代码
“周期性”法:
for(int i = 1, j = 0; i < n; ++i) { while(j && s[i] != s[j]) j = kmp[j]; if(s[i] == s[j]) ++j; kmp[i + 1] = j; } for(int i = 1; i <= n; ++i) { dp[i] = dp[i - 1] + t0[s[i - 1] - 'a']; const int x = i - kmp[i]; if(x) { const int j = ((i + x - 1) / x + 1) / 2 * x; dp[i] = min(dp[i], dp[j] + t1 + 1LL * t2 * (2 * j - i)); } } cout <<dp[n] <<'\n';“转移点”法:
for(int i = 1, j = 0; i < n; ++i) { while(j && s[i] != s[j]) j = kmp[j]; if(s[i] == s[j]) ++j; kmp[i + 1] = j; } dp[0] = t0[s[0] - 'a']; for(int i = 1, j = 0; i < n; ++i) { dp[i] = dp[i - 1] + t0[s[i] - 'a']; while(j && s[i] != s[j]) j = kmp[j]; if(s[i] == s[j]) ++j; while(j << 1 > i + 1) j = kmp[j]; if(j) dp[i] = min(dp[i], dp[i - j] + t1 + 1LL * t2 * (i + 1 - 2 * j)); } cout <<dp[n - 1] <<'\n';