湖南师范大学2018年大学生程序设计竞赛新生赛补题

模拟不想写,其他题目手残导致“爆零“”

https://ac.nowcoder.com/acm/contest/127

小小粉刷匠

状态设计:假设将一个区间刷完最多需要x次(一个一个刷),当(a[i]==a[j])时,这样在决策当前区间的时候一次将整个区间刷成"(a[i])"后,这时次数相对于一个一个刷减少了一次

若不相同,则就是两个区间合并成一个区间,即把它们都刷成目标状态的次数加起来

由于这题限制了一次只能最多刷连续k个,所以当区间长度len>k时,一刷子不能从左刷到右,就不能通过(a[i]==a[j])进行转移,只能进行区间合并

比大部分题解的代码都简介,状态也更优

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
const int maxn = 1e6 + 10;
const int inf = 1e6;
ll mod = 1e9 + 7;

int dp[200][200];
int main()
{
    //freopen("C:\1.in", "r", stdin);
    fastio;
    int n, k;
    cin >> n >> k;
    vector<int>a(n + 1);
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        dp[i][i] = 1;
    }
    for (int len = 2; len <= n; len++)
    {
        for (int l = 1; l <= n - len + 1; l++)
        {
            int r = l + len - 1;
            if (len <= k && a[l] == a[r])
                dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]);
            else
                for (int q = l; q < r; q++)
                    dp[l][r] = min(dp[l][r], dp[l][q] + dp[q + 1][r]);
        }    
    }
    cout << dp[1][n];
    return 0;

}

巨巨的提问

状态设计:开dp数组dp[i][j][k],其中第一维为当前位置,第二维为当前多出的左括号个数(左-右必然得>=0),第三维为当前位置是否修改(连续修改不消耗次数,所以记录这个状态去转移连续修改)

每新增一个括号时,都去记录修改它和不修改它两种状态所需的最小花费

转移过程写在注释

9/14/2020 update:开3维记录上一个位置的每个状态,很好的处理了只有(这个转移只有第一第三维)二维 没有的无后效性。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
const int maxn = 1e6 + 10;
const int inf = 1e6;
ll mod = 1e9 + 7;

int dp[2005][2005][2];
int main()
{
    fastio;
    int n;
    cin >> n;
    memset(dp, 0x3f, sizeof(dp));
    string s;
    cin >> s;
    s = '0' + s;
    dp[0][0][0] = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = i; j >= 0; j--)//枚举多出的左括号数(从$dp[0][0][0]$开始转移的,因此不合法状态不会被转移,所以从i位全是括号开始枚举)
        {
            if (s[i] == '(')
            {
                if (j)
                    dp[i][j][0] = min(dp[i - 1][j - 1][0], dp[i - 1][j - 1][1]);//假设不修改,则比上一个状态多了一个左括号
                dp[i][j][1] = min(dp[i - 1][j + 1][0] + 1, dp[i - 1][j + 1][1]);//如果修改,则匹配一个左括号
            }
            else
            {
                dp[i][j][0] = min(dp[i - 1][j + 1][0], dp[i - 1][j + 1][1]);//假设不修改,则匹配了上一个状态的一个左括号
                if (!j)continue;
                dp[i][j][1] = min(dp[i - 1][j - 1][0] + 1, dp[i - 1][j - 1][1]);//假设修改,则在上一个状态上加一个左括号
            }
        }
    }
    cout << min(dp[n][0][0], dp[n][0][1]);
    return 0;

}
原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/13526279.html