Gym-102465k Dishonest Driver题解

Gym-102465k Dishonest Driver

给出一个字符串,两个相邻且相同子串可以进行压缩,问压缩后字符串最少有多少字符,\(n \le 700\)

将两个相邻区间合并,且 \(n\) 很小,就很像是区间 DP。
定义 \(dp_{i, j}\) 表示 \([i, j]\) 的压缩后最少字符数。
显然有两种合并,直接拼起来相加,或者将右区间压缩。
考虑怎么维护能否拼接,我们用两个数组辅助。
\(a_{i,j}\) 表示 \([i,j]\)\([j+1, j+j-i+1]\) 是否相同。
\(b_{i,j}\) 表示 \([i,j]\) 中最后一个循环节的开始位置。

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define FL(a,b,c) for(int a=(b),a##end=(c);a<=a##end;++a)
#define FR(a,b,c) for(int a=(b),a##end=(c);a>=a##end;--a)
#define lowbit(x) ((x)&-(x))
#define eb emplace_back
#define SZ(x) (int)((x).size())
#define ll long long
#define vt vector
#define fr first
#define se second
#define mmt(x, y) memset(x, y, sizeof x)
#define PII pair<int, int>
#define max(a, b)({auto f7r=(a);auto j3h=(b);f7r<j3h?j3h:f7r;})
#define cmax(a, b)({auto j3h=(b);(j3h>a)&&(a=j3h);})
#define min(a, b)({auto f7r=(a);auto j3h=(b);f7r>j3h?j3h:f7r;})
#define cmin(a, b)({auto j3h=(b);(j3h<a)&&(a=j3h);})
constexpr int N = 700 + 10;
char s[N];
int dp[N][N], a[N][N], b[N][N], n, u;
int32_t main(){
    cin.tie(0)->sync_with_stdio(0);
    cin >> n >> s + 1, mmt(dp, 0x3f);
    FL(i, 1, n)dp[i][i] = 1;
    FL(i, 1, n)FL(j, i, n){
        int flag = 1;
        for(int k = 0; i + k <= j && j + k <= n; k++)
            if(s[i + k] != s[j + k + 1]){flag = 0;break;}
        if(flag)a[i][j] = 1, b[i][j] = i;
    }
    FR(i, n, 1)FL(j, i + 1, n)FL(k, i, j){
        cmin(dp[i][j], dp[i][k] + dp[k + 1][j]), u = b[i][k];
        if(u && a[u][k] && k - u + 1 == j - k)
            cmin(dp[i][j], dp[i][k]), b[i][j] = k + 1;
    }
    cout << dp[1][n] << endl;
    return 0;
}

参考文献:Gym-102465-部分题解 - rwbyblake的博客

posted @ 2025-08-06 15:53  fush's_blog  阅读(12)  评论(0)    收藏  举报