poj 1159 Palindrome(lcs类似dp)

时间:2023-02-23 12:03:49

题意:问一个字符串最少插入多少个字符可以将其变成回文串。

思路:

f(i, k) 为 从i开始长度为k 的字串变成回文串最少需要插入字符数。

看见discuss明白了这个口以看作 原串长-正逆串lcs。。

不过开二维数组会mle, 不过貌似空间减半就可以了,所以直接有人用压缩矩阵或者改用short。。

我用f1,f2分别保存上个和上上个状态,空间消耗5000*2。。

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <climits>
#include <set>
#include <map>
using namespace std;

#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))

typedef long long LL;

const int Maxn = 5000;
const int inf = INT_MAX/2;
char a[Maxn+5];
int f1[Maxn+5], f2[Maxn+5], len;

int f(int l, int r) {
    if (l >= r) return 0;
    if (r-l+1 == len-2) return f2[l];
    return f1[l];
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    SPEED_UP
    int n;
    cin >> n >> a;

    rep(k, 2, n)
        rep(i, 0, n-k) {
            int j = i+k-1, tmp = inf;
            len = k;
            tmp = min(f(i+1, j), f(i, j-1))+1;
            if (a[i] == a[j])
                tmp = min(tmp, f(i+1, j-1));
            else
                tmp = min(tmp, f(i+1, j-1)+2);
            f2[i] = f1[i];
            f1[i] = tmp;
            //cout << "f(" << i << ", " << j << ") " << f[i][j] << endl;
        }
    cout << f(0, n-1) << endl;
    return 0;
}