题解 CF1353E K-periodic Garland

2021/4/12 10:25:37

本文主要是介绍题解 CF1353E K-periodic Garland,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

CF1353E K-periodic Garland

由题意,每个位置上有且只有 \(0/1\) 两种状态,且我们若是求出前缀和就能快速得出其中某一段中 \(1\) 的个数。

首先看一下如果让我们构造怎么构造。我们要构造一个 \(1\) 之间距离恰好为 \(k\) 的序列,就是说位置上的状态每次转移到 \(1\) ,都必须转移回到 \(0\) ,在 \(0\) 的状态呆 \(k\) 次再转移回 \(1\) 状态。

画出状态机如下:

由这个图我们先得出一个暴力且错误的状态转移方程:

\(f(i)=f(i-k)+sum(i-1)-sum(i-k)+[s_i=0]\),其中\(f(i)\) 表示构造第一位是 \(1\) 的序列需要改造的步数 ,\(sum\) 是原来序列的前缀和,\(s_i\) 是原序列。

这个东西为什么错误?因为我们不敢说第一位一定是 \(1\),说不定答案的序列开头很长一段都是 \(0\)。我们首先想到,这个问题可以大力枚举前面 \(0\) 的位数解决。假设我们把前 \(i-1\) 位设为 \(0\),第 \(i\) 位设成 \(1\) 的代价为 \(g(i)\),我们很容易得到:\(g(i)=sum(i-1)+[s_i=0]\)。

我们修改状态 \(f(i)\) 为到第 \(i\) 位为 \(1\) 时,前面均合法且至少有一个 \(1\) 的最小代价。

那么我们可以得到状态转移方程:\(f(i)=min(\ f(i-k),\ g(i-k)\ )+sum(i-1)-sum(i-k)+[s_i=0]\)。

我们的后缀仍然有可能全是 \(0\) ,所以统计答案时,我们枚举构造序列长度 \(i\) ,同时维护一个值 \(z\) 表示将以 \(i+1\) 为起点的后缀全部设为 \(0\) 的代价。答案就是 \(Min_{i=1}^nmin(\ f(i)\ ,\ g(i)\ )+z(i)\)

个人感觉难度 绿-蓝

#include <bits/stdc++.h>
using namespace std;

const int N=4e6+10;
int f[N],g[N],sum[N];
char str[N];

int main()
{
	int t; cin>>t;
	while(t--)
	{
		int n,k;
		cin>>n>>k>>(str+1);
		for(int i=0;i<=n;i++) f[i]=0x3f3f3f3f,sum[i]=0;
		for(int i=1;i<=n;i++)
			sum[i]=sum[i-1]+(str[i]-'0'), g[i]=sum[i-1]+int(str[i]=='0');
		for(int i=1;i<=n;i++)
			if(i>k) f[i]=min(f[i-k],g[i-k])+sum[i-1]-sum[i-k]+int(str[i]=='0');
		int ans=sum[n];
		for(int i=1;i<=n;i++)
			ans=min(ans,min(f[i],g[i])+sum[n]-sum[i]);
		cout<<ans<<'\n';
	}
	return 0;
}


这篇关于题解 CF1353E K-periodic Garland的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程