哇很好的题..
发现在dp中,找到"转化的一步",枚举这一步非常重要.
这题首先是n2的处理出区间回文,一开始我一直想的是dp[i][j]来代表[i,j]之间最少划分几个,这个是容易的,但是会t,我想了几个优化,其中一个便是不是遍历i,j中间每一个点,而是直接选p,[i,p]为回文串,这样可以提高速度,但是仍然不够.我就想换一个状态.
dp[i],前i个最少划分几个,其实这个我很早有想到,但是不知道在利用前面的i时,中间那一段是处理不出来的,后来发现没有必要,只需要遍历从右端点往左的每一个回文串,就可以了.因为显然这样也可以"覆盖全部状态".
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef long long LL;
const int MAXN = 5e3 + 17;
const int MOD = 1e9 + 7;
bool dp[MAXN][MAXN];
int dpx[MAXN];
vector<int> vec[MAXN];
int main(int argc, char const* argv[])
{
#ifdef noob
freopen("Input.txt", "r", stdin);
freopen("Output.txt", "w", stdout);
#endif
string str;
cin >> str;
int n = str.length();
for (int i = 0; i < n; ++i) {
dp[i][i] = 1;
}
for (int i = 0; i < n - 1; ++i) {
if (str[i] == str[i + 1])
dp[i][i + 1] = 1;
}
for (int l = 3; l < n; ++l) {
for (int i = 0; i + l - 1 < n; ++i) {
int j = i + l - 1;
if (str[i] == str[j])
dp[i][j] = dp[i + 1][j - 1];
}
}
for (int j = 0; j < n; ++j) {
if (dp[0][j])
dpx[j] = 1;
else
dpx[j] = 19990317;
}
for (int i = 0; i < n; ++i) {
for (int j = i; j < n; ++j) {
if (dp[i][j]) {
vec[j].push_back(i);
}
}
}
for (int j = 0; j < n; ++j) {
for (auto i : vec[j])
dpx[j] = min(dpx[j], dpx[i - 1] + 1);
}
cout << dpx[n - 1] << endl;
return 0;
}