luogu P1777
要实现的操作过于复杂。
考虑先取出, 后插入, 对答案没有影响, 最后的答案就是取出后剩余的序列形成的段的数量加上取出来的集合中拥有的剩余的集合中没有的元素的数量, 即设剩余集合为 S, 取出集合为 H, 那么刚才说的加上的那个数就是 |S\H|。
设状态为 (i,j,lS,lcol), 即从左扫描到第 i 个数, 取出了 j 次, 留下的颜色集合为 lS, 留下序列的结尾颜色为 lcol, f(i,j,lS,lcol) 表示当前状态的最小的 mess 值。
转移方程:
留下当前数:f(i,j,lS|col[i],col[i]).check_min by f(i-1,j,lS,lcol) + [lcol != col[i]]
不留下:f(i,j,lS,lcol).check_min by f(i-1,j-1,lS,lcol)
实现的时候当然是要选择当前状态更新后续状态的实现。
初始状态就设在 i = 1 的时候。
#include<bits/stdc++.h>
using namespace std;
int n,k,col[103];
int f[103][103][1<<8][9];
void cmin(int &x, int v) {
x = min(x, v);
}
int calc(int s) {
int res = 0;
for(int i=0; i<8; ++i) res += ((s>>i)&1);
return res;
}
int main() {
int id = 0;
while(scanf("%d%d",&n,&k) == 2 && n && k) {
int all_S = 0;
for(int i=1; i<=n; ++i) scanf("%d", &col[i]), all_S |= (1<<(col[i]-25));
memset(f, 0x3f, sizeof f);
// -24 = use_col !!!
f[1][1][0][0] = 0;
f[1][0][1<<(col[1]-25)][col[1]-24] = 1;
for (int i=1; i<n; ++i) {
for (int j=0; j<=min(i,k); ++j) {
for (int lS=0; lS<(1<<8); ++lS) {
for (int lcol=0; lcol<9; ++lcol) {
if (f[i][j][lS][lcol] == 0x3f3f3f3f) continue;
int ncol = col[i+1];
cmin(f[i+1][j][lS|(1<<(ncol-25))][ncol-24], f[i][j][lS][lcol] + (lcol != (ncol-24)));
if(j<k) cmin(f[i+1][j+1][lS][lcol], f[i][j][lS][lcol]);
}
}
}
}
int ans = 0x3f3f3f3f;
for (int lcol = 0; lcol < 9; ++lcol) {
for (int S = all_S; S; S = (S-1)&all_S)
cmin(ans, f[n][k][S][lcol] + calc(S ^ all_S));
cmin(ans, f[n][k][0][lcol] + calc(all_S));
}
// cout << ans << '\n';
printf("Case %d: %d\n\n", ++id, ans);
}
return 0;
}