• [ICPC2020昆明C] Cities


    [ICPC2020昆明C] Cities - 区间dp

    Description

    给定长度为 (n(nle 5000)) 的序列 (a),一次操作你可以选择一个数值相同的连续区间,将这个区间的数值修改为其他数。问多少进行多少次操作能使得区间所有数相同。每种 (a_i) 最多出现 (15)

    Solution

    首先我们先把相同连续的变成一个,这样相邻元素永远不相同

    (f[i][j]) 表示把区间 ([i,j]) 搞成和位置 (j) 颜色一样,需要的最小代价

    转移有两种

    最后单独多一步,即 (f[i][j] leftarrow f[i][j-1]+1)

    找中间一个和 (j) 颜色相同的位置 (l)(f[i][j] leftarrow f[i][l] + f[l+1][j])

    这就是为什么题目中限制了每种元素的个数

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5005;
    
    int m, s[N], n, a[N], pre[N], f[N][N], buf[N];
    
    void solve()
    {
        cin >> m;
        for (int i = 1; i <= m; i++)
            cin >> s[i];
        n = 0;
        a[++n] = s[1];
        for (int i = 2; i <= m; i++)
            if (s[i] != s[i - 1])
                a[++n] = s[i];
        memset(buf, 0, sizeof buf);
        for (int i = 1; i <= n; i++)
            pre[i] = buf[a[i]], buf[a[i]] = i;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                f[i][j] = 1e9;
        for (int i = 1; i <= n; i++)
            f[i][i] = 0, f[i + 1][i] = 0;
        for (int len = 1; len < n; len++)
        {
            for (int i = 1; i + len <= n; i++)
            {
                int l = i, r = i + len;
                f[l][r] = f[l][r - 1] + 1;
                for (int p = pre[r]; p >= l; p = pre[p])
                {
                    f[l][r] = min(f[l][r], f[l][p] + f[p + 1][r]);
                }
            }
        }
        cout << f[1][n] << endl;
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int t;
        cin >> t;
        while (t--)
            solve();
    }
    
  • 相关阅读:
    在navgationController中添加UISegmentedControl
    Static Const
    .pch头文件的添加
    数据库设计一对一多对多
    数据库链接
    File增删改查
    线程
    售票情景解读synchronized和Lock两种锁的区别
    [Spring Boot]使用自定义注解统一请求返回值
    JAVA希尔排序代码
  • 原文地址:https://www.cnblogs.com/mollnn/p/14623673.html
Copyright © 2020-2023  润新知