[codeforces 1353E] K-periodic Garland 为什么会想到动归dp

Codeforces Round #642 (Div. 3)  参与排名人数11823

[codeforces 1353E]   K-periodic Garland   为什么会想到动归dp

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址http://codeforces.com/contest/1353/problem/E

ProblemLangVerdictTimeMemory
E - K-periodic Garland GNU C++17Accepted46 ms12400 KB

 思路来自对数据的分析:

以n=4,k=2为例
有16种形态
0000符合题意
0001符合题意
0010符合题意
0011
0100符合题意
0101符合题意
0110
0111
1000符合题意
1001
1010符合题意
1011
1100
1101
1110
1111

动归dp的目标不是枚举所有情况,而是符合题意的情况一个都不会漏,符合题意的形态有7种
0000
0001
0010
0100
0101
1000
1010

通过对以下数据进行归纳,容易得出对应的动归dp的写法,对这7种形态,归类,找规律
1000注意,最后一个1,后面全是0
1010注意,最后一个1,后面全是0.(1010与1000有递推关系)
0100注意,最后一个1,后面全是0
0101注意,最后一个1,后面正好数据据终结.(0101与0100有递推关系)
0010注意,最后一个1,后面全是0
0001注意,最后一个1,后面正好数据据终结
0000注意,全是0

考虑如下输入数据
4 2
1111

1111变换到0000,需变动4个数据
1111变换到1000,需变动3个数据
1111变换到1010,需变动2个数据
1111变换到0100,需变动3个数据
1111变换到0101,需变动2个数据
1111变换到0010,需变动3个数据
1111变换到0001,需变动3个数据

取最小值2,
输出2

通过上述过程可以看到:
0000可采用特判。
初始化为1000,0100,0010,0001这几种形态,
其它符合题意的形态都可以由初始化的形态推得。

根据上述数据分析,容易得到动归dp对应的算法如下:

dp[i]记录字串[1,i]区间满足题意的周期性质,第i位为必须为1,需要更新原字符串中的值的最小个数(1变0,记1次;0变1,记1次)

AC代码如下

#include <cstdio>
#include <algorithm>
#define maxn 1000010
using namespace std;
char s[maxn];
int sum[maxn],dp[maxn];//dp[i]记录字串[1,i]区间满足题意的周期性质,第i位为必须为1,需要更新原字符串中的值的最小个数(1变0,记1次;0变1,记1次)
int main(){
	int t,n,k,i,ans;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%s",&n,&k,s+1);
		for(i=1;i<=n;i++)sum[i]=sum[i-1]+s[i]-'0';//sum[]采用前缀和的方式记录字符串中1的个数
		for(i=1;i<=n;i++)dp[i]=sum[i-1]+(s[i]=='0');//处理字串[1,i]区间,目标(第i位为1,[1,i-1]全为0),字串需要变动的个数
		for(i=k+1;i<=n;i++)//要涉及起始位置,以及之后一个周期的k个数,故每次需处理连续的k+1个数
			dp[i]=min(dp[i],dp[i-k]+sum[i-1]-sum[i-k]+(s[i]=='0'));//dp[i-k]对应字串[1,i-k]区间满足题意的周期性质,第i-k位为必须为1,需要更新原字符串中的值的最小个数(1变0,记1次;0变1,记1次).sum[i-1]-sum[i-k]对应原字串区间[i-k+1,i-1]中1的个数.(s[i]=='0'),对应,第i位为必须为1,该位必须更新的次数。
		ans=sum[n];//对应更新后的字串全是0,需要更新的个数,即原字串中的1全部变更为0
		for(i=1;i<=n;i++)
			ans=min(ans,dp[i]+sum[n]-sum[i]);//请注意,区间[i+1,n]原字串的1全部变更为0.sum[n]-sum[i]对应原字串区间[i+1,n]中1的个数.
		printf("%d\n",ans);
	}
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值