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;
}
posted @ 2021-05-24 17:14  enisp  阅读(42)  评论(0)    收藏  举报