2021ICPC昆明C.Cities

题意描述
原题链接
Solution
首先想到一些性质
如果序列数全都不相同,则修改次数为n-1,若一段区间l,r端点数相同,
则一定是把中间的数修改成端点的值。且序列都不同,则可以在同一个操作下,修改成区间的任意一个数,同理,可以把区间相同的一段再看成一个点,则区间在最短的操作次数下,一定能修改成端点的值。
我 们 设 d p [ l ] [ r ] 为 l , r 最 小 的 修 改 次 数 我们设dp[l][r]为l,r最小的修改次数 dp[l][r]l,r
首先 d p [ l ] [ r ] = m i n ( d p [ l + 1 ] [ r ] + 1 , d p [ l ] [ r − 1 ] + 1 ) dp[l][r]=min(dp[l+1][r]+1,dp[l][r-1]+1) dp[l][r]=min(dp[l+1][r]+1,dp[l][r1]+1),也就是区间拓展过来,不考虑任何特殊情况
若a[l]==a[r],则有, d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l + 1 ] [ r − 1 ] + 1 ) dp[l][r]=min(dp[l][r],dp[l+1][r-1]+1) dp[l][r]=min(dp[l][r],dp[l+1][r1]+1),中间的数变成a[l]即可
再考虑若区间再中间的情况,即是 d p [ l ] [ r ] dp[l][r] dp[l][r]中存在 a [ k ] = = a [ r ] a[k]==a[r] a[k]==a[r]
枚举每个 l < k < r , 若 a [ k ] = = a [ r ] , 则 d p [ k ] [ r ] 的 值 就 是 变 成 a [ k ] 的 最 小 操 作 数 , 再 把 左 侧 区 间 d p [ l ] [ k − 1 ] 变 成 a [ k ] 即 可 l<k<r,若a[k]==a[r],则dp[k][r]的值就是变成a[k]的最小操作数,再把左侧区间\\ dp[l][k-1]变成a[k]即可 l<k<r,a[k]==a[r],dp[k][r]a[k]dp[l][k1]a[k]
若 a [ k ] = = a [ r ] , d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ k ] [ r ] + d p [ l ] [ k − 1 ] + 1 ) 若a[k]==a[r],dp[l][r]=min(dp[l][r],dp[k][r]+dp[l][k-1]+1) a[k]==a[r],dp[l][r]=min(dp[l][r],dp[k][r]+dp[l][k1]+1)
若 此 时 a [ k ] = = a [ l ] , 左 侧 也 不 需 要 那 个 + 1 , 因 为 本 身 就 是 a [ k ] 若此时a[k]==a[l],左侧也不需要那个+1,因为本身就是a[k] a[k]==a[l],+1a[k]
故: a [ k ] = = a [ l ] 且 a [ l ] = = a [ r ] 时 a[k]==a[l]且a[l]==a[r]时 a[k]==a[l]a[l]==a[r],
d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l ] [ k ] + d p [ k ] [ r ] ) dp[l][r]=min(dp[l][r],dp[l][k]+dp[k][r]) dp[l][r]=min(dp[l][r],dp[l][k]+dp[k][r])
其 实 仔 细 思 考 此 时 d p [ l ] [ k ] 和 d p [ l ] [ k − 1 ] 应 该 等 效 , 都 能 表 示 成 全 是 a [ k ] 的 最 小 操 作 数 , 故 写 成 d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l ] [ k − 1 ] + d p [ k + 1 ] [ r ] ) 也 可 其实仔细思考此时dp[l][k]和dp[l][k-1]应该等效,\\都能表示成全是a[k]的最小操作数 ,故写成\\dp[l][r]=min(dp[l][r],dp[l][k-1]+dp[k+1][r])也可 dp[l][k]dp[l][k1],a[k],dp[l][r]=min(dp[l][r],dp[l][k1]+dp[k+1][r])
因 为 枚 举 k 会 n 3 , 而 其 实 每 个 数 最 多 出 现 15 , 我 们 只 需 要 存 一 下 每 个 数 上 一 次 出 现 位 置 就 行 时 间 复 杂 度 O ( 15 n 2 ) 因为枚举k会n^3,而其实每个数最多出现15,我们只需要存一\\下每个数上一次出现位置就行\\ 时间复杂度O(15n^2) kn3,15,O(15n2)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize(3, "Ofast", "inline")
#define fir(i, a, b) for (int i = a; i <= b; i++)
#define mov(i) (1ll << i)
#define MAX_INF 0x3f3f3f3f
const int maxn = 5e3 + 10;
int a[maxn];
int b[maxn];
int dp[maxn][maxn];
int pre[maxn], pos[maxn];
int dfs(int l, int r)
{
    if (l == r)
        return 0;
    if (dp[l][r] != MAX_INF)
        return dp[l][r];
    dp[l][r] = min(dfs(l + 1, r) + 1, dfs(l, r - 1) + 1);
    if (b[l] == b[r])
        dp[l][r] = min(dp[l][r], dfs(l + 1, r - 1) + 1);
    for (int k = pre[r]; k > l; k = pre[k])
    {
        if (b[l] == b[r])
            dp[l][r] = min(dp[l][r], dfs(l, k - 1) + dfs(k + 1, r));
        else
            dp[l][r] = min(dp[l][r], dfs(l, k - 1) + dfs(k, r) + 1);
    }
    return dp[l][r];
}
int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        fir(i, 1, n) scanf("%d", &a[i]);
        int m = 0;
        fir(i, 1, n) pre[i] = 0, pos[i] = 0;
        fir(i, 1, n)
        {
            if (a[i] != b[m])
            {
                b[++m] = a[i];
            }
        }
        n = m;
        if (n == 1)
        {
            puts("0");
            return 0;
        }
        fir(i, 1, n)
        {
            int &x = b[i];
            pre[i] = pos[x];
            pos[x] = i;
        }
        fir(i, 1, n)
            fir(j, 1, n) dp[i][j] = MAX_INF;
        printf("%d\n", dfs(1, n));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值