【DP】E. K-periodic Garland
题意:给定长度为n的01字符串,每次操作可以改变一个字符的状态,问使字符串中相邻1的距离为k的最小操作次数
思路:
DP。
\(pre[i]\)记录前\(i\)项中\(1\)的个数
\(dp[i][0]\)为使得前\(i\)项都合法,第\(i\)位为\(0\)时的最小操作次数
\(dp[i][1]\)为使得前\(i\)项都合法,第\(i\)位为\(1\)时的最小操作次数
那么转移方程
$dp[i][0]=min(dp[i-1][0],dp[i-1][1])+(s[i]==1) $
因为第\(i\)项为\(0\)时对合法性无影响,其合法性可以直接从\(dp[i-1][0]或者dp[i-1][1]\)转移过来,操作次数更新由\(s[i]==1\)负责,若\(s[i]\)本身就为0,则新增0次操作,否则新增1次操作
\(dp[i][1]=min(dp[i-k][1]+pre[i-1]-pre[i-k],pre[i-1])+(s[i]==0)\)
当第\(i-k\)项合法时,要使第\(i\)项为\(1\)时合法,则要保证第\(i-k+1\)项到第\(i-1\)项都为\(0\),第\(i\)项才能为\(1\)(此时\(pre[i-1]-pre[i-k]=0\)),\(dp[i][1]\)的状态才能从\(dp[i-k][1]\)转移过来;或者从“令\(1\)到\(i-1\)项全为\(0\),使得第\(i\)项为整个序列的第一个\(1\)”的状态转移过来。操作次数更新由\(s[i]==0\)负责,若\(s[i]\)本身就为1,则新增0次操作,否则新增1次操作
最后注意输入的是字符数组
void solve() {
int n, k;
cin >> n >> k;
cin >> s+1;
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] + (s[i] == '1');
for (int i = 1; i <= n; i++) {
int p = max(0, i - k);
dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]) + (s[i] == '1');
dp[i][1] = min(dp[p][1] + pre[i - 1] - pre[p], pre[i - 1]) + (s[i] == '0');
}
cout << min(dp[n][0], dp[n][1]) << endl;
for (int i = 0; i <= n; i++) {
dp[i][1] = 0;
dp[i][0] = 0;
pre[i] = 0;
}
}