SCOI2003 字符串折叠 【动态规划】
折磨啊,这题
调了一个上午加大半个下午,就因为一个非常的小的小bug
直接区间dp,转移分两种情况:1. 整个区间可以被折叠。 2. 整个区间可以被两个更小的区间拼起来
为什么不需要考虑一个区间又折叠又拼呢?因为这些操作都可以被包含在第二个转移情况中
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#define gi get_int()
const int MAXN = 200, BASE = 233;
int get_int()
{
int x = 0, y = 1;
char ch = getchar();
while (!isdigit(ch) && ch != '-')
ch = getchar();
if (ch == '-')
y = -1, ch = getchar();
while (isdigit(ch))
x = x * 10 + ch - '0', ch = getchar();
return x * y;
}
unsigned long long HASH[MAXN];
int dp[MAXN][MAXN];
unsigned long long qPow(int x, int y)
{
unsigned long long ans = 1, b = x;
while (y != 0) {
if (y & 1)
ans *= b;
b *= b;
y >>= 1;
}
return ans;
}
unsigned long long getHash(int start, int len)
{
return HASH[start + len - 1] - (start == 0 ? 0 : HASH[start - 1] * qPow(BASE, len));
}
int main()
{
freopen("code.in", "r", stdin);
freopen("code.out", "w", stdout);
std::string str;
std::cin >> str;
int n = str.size();
for (int i = 0; i < n; i++)
HASH[i] = str[i] + (i == 0 ? 0 : HASH[i - 1] * BASE);
memset(dp, 0x3f, sizeof(dp));
for (int i = 0; i < n; i++)
dp[i][i] = 1;
for (int size = 1; size < n; size++) {
for (int i = 0; i < n; i++) {
int j = i + size;
for (int k = 1; k <= (j - i + 1); k++) {
if ((j - i + 1) % k != 0) continue;
unsigned long long num = getHash(i, k), flag = 0;
for (int l = i; (k != 1 && l < j) || (k == 1 && l <= j); l += k) { // 这一行调了我一个下午,因为这里判的是左端点,那么当左端点等于右端点时就需要l<=j而不是小于了
if (getHash(l, k) != num) {
flag = 1;
break;
}
}
if (flag == 1) continue;
int len = (j - i + 1) / k;
dp[i][j] = std::min(dp[i][j], dp[i][i + k - 1] + 2 + (len < 10 ? 1 : 2));
}
for (int k = i; k < j; k++) {
dp[i][j] = std::min(dp[i][j], dp[i][k] + dp[k + 1][j]);
if (dp[0][11] == 5) {
std::cout << i << ' ' << j << std::endl;
std::cout << "fuck" << ' ' << k << ' ' << dp[i][k] << ' ' << dp[k + 1][j];
return 0;
}
}
}
}
std::cout << dp[0][n - 1];
return 0;
}

浙公网安备 33010602011771号