Cities (2020ICPC-昆明)(区间dp)
题意
给出一个长度为n的序列,序列中每个元素均小于等于n,每次可以将序列中连续且相等的区间变为其他的值(更改后的当然也必须小于等于n)。 求:最小的操作次数,使得长度为n的序列所有的元素均相同。
Input
2 8 4 3 1 2 1 1 3 3 5 1 2 3 2 1
Output
2 8 4 3 1 2 1 1 3 3 5 1 2 3 2 1
思路
区间dp。
- 假设原序列为a[n]
- 首先将序列中相邻且相同的元素合并,也即删掉相邻的相同元素(剩下的元素为m, 然后令n = m)
- 对于一段区间[ l, r], 用最少的次数变为相同的颜色,这个区间的颜色最终一定可以变为a[l]或a[r]
- 考虑如何减少操作:显然,如果n个元素互不相同,则最少操作次数为 n - 1;否则,假设a[l] = a[r],那么将a[l + 1, r - 1] 涂为 a[l] 或 a[r],可减少一次操作。
- f[ l ][ r ]表示将区间[ l, r ]变为相同的颜色的最小操作次数
- 设pre[ a[ i ] ] 表示 a[i] 在 i 之前最近一次出现的位置(例如:2 3 1 4 3 5, a[5] = 3, pre[a[5]] = 2)
- 状态转移 f [ l ] [ r ] = { m i n ( f [ l ] [ r ] , f [ l ] [ k ] + f [ k + 1 ] [ r ] ) a[k] == a[r]) m i n ( f [ l ] [ r ] , f [ l + 1 ] [ r ] + 1 , f [ l ] [ r − 1 ] + 1 ) else f[l][r] = egin{cases}min(f[l][r], f[l][k] + f[k + 1][r]) & ext{a[k] == a[r])}\ min(f[l][r], f[l + 1][r] + 1, f[l][r - 1] + 1) & ext{else}end{cases} f[l][r]={ min(f[l][r],f[l][k]+f[k+1][r])min(f[l][r],f[l+1][r]+1,f[l][r−1]+1)a[k] == a[r])else 前者表示区间[l, r - 1]存在和a[r]相同的a[k], 后者表示不存在这样的a[k] 存在a[k] = a[r]时:区间[l, k]涂为a[k], 区间[k + 1, r]涂为a[r]即可(由于a[k] = a[r],所以这样可以减少一次 操作) 不存在a[k] = a[r]时:那么f[l, r]可直接由区间长度比[l, r]少1的区间[l, r - 1]或者[l + 1, r]转移过来
CODE
const int N = 5e3 + 6; int f[N][N]; int a[N], mp[N], pre[N]; int main() { IOS; int T; cin >> T; while (T--) { int n; cin >> n; int m = 0; for (int i = 1; i <= n; i++) { cin >> a[i]; if (a[i] == a[i - 1]) i--, n--; else m++; } for (int i = 1; i <= m; i++) mp[i] = pre[i] = 0; for (int i = 1; i <= m; i++) { pre[i] = mp[a[i]]; mp[a[i]] = i; } for(int i = 1; i <= m; i++) for (int j = 1; j <= m; j++) { if (i == j) f[i][i] = 0; else f[i][j] = inf; } for (int len = 2; len <= m; len++) { for (int l = 1; l <= m - len + 1; l++) { int r = l + len - 1; int& x = f[l][r]; //若不存在与a[r]相同的颜色,则直接转移即可 if(a[l] != a[r]) x = min({ x, f[l + 1][r] + 1, f[l][r - 1] + 1 }); //存在与a[r]相同的颜色,则减少其操作次数 for (int k = pre[r]; k >= l; k = pre[k]) x = min(x, f[l][k] + f[k + 1][r]); } } cout << f[1][m] << endl; } return 0; }
总结
dp最重要的还是要定义好状态以及不漏的将状态转移。看了好多篇题解,都是写的一知半解(幽灵),而且状态转移的时候都不太清楚,转移方程都有交集。。所以我费了好久写了一篇自己的理解。。
下一篇:
希尔排序——C语言实现