第二篇博客 codeforces round #642 div3

本文精选两道算法竞赛题目,包括构造数组问题和周期性花环问题,详细解析了使用优先队列和动态规划的解决方案,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Constructing the Array

题目链接:点击查看
题目描述:

给一个n个0的数组,每次都去寻找最左边的最长连续0子段的中间位置进行赋值。

题目分析:

可以使用优先队列进行解决,每次都是将node(l,r)添加进去,每次取出来的都是连续0长度最长或者是最左边的段。

代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200005];
struct node{
	int l;
	int r;
	node(int x,int y){
		l=x;
		r=y;
	}
	bool operator < (const node & temp)const{
		if(r-l==temp.r-temp.l){
			return temp.l < l;//相等长度,左边优先 
		}
		return temp.r-temp.l>r-l;
	}
};
priority_queue<node> q;
void bfs(){
	int cnt=0;
	q.push(node(1,n));
	while(!q.empty()){
		node temp = q.top();
		q.pop();
		if(temp.l>temp.r)continue;
		int mid = (temp.l+temp.r)>>1;
		a[mid]=++cnt;
		q.push(node(temp.l,mid-1));
		q.push(node(mid+1,temp.r));
	}
}
int main()
{
	int t;
	cin >> t;
	while(t--){
		scanf("%d",&n);
		bfs();
		for(int i = 1; i <= n; ++i){
			printf("%d ",a[i]);
		}
		cout << endl;
	}
	return 0;
}

E. K-periodic Garland

题目链接:点击查看
题目描述:

给一个01字符串,每次操作改变一个字符状态,使得字符串中1的相邻距离为k,问最少操作数。

题目分析:

可以使用dp进行解决。

sum[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时的状态,那么此处为0对前面是否正确不影响,可以直接
从dp[i−1][0]或者dp[i−1][1]转移过来,如果s[i]==‘1’,那么操作数加1。

  • dp[i][1]=min(dp[i−k][1]+sum[i−1]−sum[i−k],sum[i−1])+(s[i]==‘0’)

当前记录第i项为1时的状态,如果前i−k项合法时,要使第i项为1时合法,需要我们使第i−k+1项到第i−1项都为0,第i项才能为1,这也就是为什么要记录前缀和1的个数。或者让前i-1项数都为0,这种情况是sum[i-1]。然后比较取小值。最后操作数会根据s[i]=='0’继续加1。

代码:
#include<bits/stdc++.h>
using namespace std;
int n,k;
int sum[1000005];
char s[1000005];
int dp[1000005][2];
int main()
{
	int t;
	cin >> t;
	while(t--){
		cin >> n >> k;  //scanf输入,下面输入字符串很难受
		cin >> s+1; 
		for(int i = 1; i <= n; ++i){
			sum[i]=sum[i-1]+(s[i]=='1');
		}
		int temp;
		for(int i = 1; i <= n; ++i){
			temp=max(0,i-k);//需要注意i-k 
			dp[i][0]=min(dp[i-1][0],dp[i-1][1])+(s[i]=='1');
			dp[i][1]=min(dp[temp][1]+sum[i-1]-sum[temp],sum[i-1])
			+(s[i]=='0');
		}
		cout << min(dp[n][0],dp[n][1]) << endl;
		for(int i = 0; i <= n; ++i){
			dp[i][0]=0,dp[i][1]=0,sum[i]=0;//别忘了初始化 
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JHL123123

赞赏随心,支持为大。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值