模拟不想写,其他题目手残导致“爆零“”
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;
}