Educational Codeforces Round 103 (Rated for Div. 2)

这篇博客探讨了在算法竞赛中如何构建满足特定条件的数组,包括寻找最大数的最小值、优化价格变化策略以及寻找图中最长简单环的方法。通过具体的代码实现,解释了如何应对这些问题,并提供了高效的解决方案。

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

Educational Codeforces Round 103 (Rated for Div. 2)

http://codeforces.com/contest/1476

A K-divisible Sum

题意:给你n和k,需要构造一个长度为n的数组a(a中数都为正整数)使得所有数之和是k的倍数,要使得a中最大的数最小,问这个最小数是多少
思路:首先a全放1和为n,全放2合为2n,如果n >= k那么n~2n之间必有k的倍数,否则先全放 ⌊ k / n ⌋ \lfloor k/n \rfloor k/n,之后选择一些位置加一必能刚好得到k

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t,n,k;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&k);
		if(n >= k)
		{
			if(n % k == 0)
				printf("1\n");
			else
				printf("2\n");
		}
		else
		{
			printf("%d\n",(k+n-1)/n);
		}
	}
	return 0;
 } 

B Inflation

题意:给你n个数字p0,p1,…,pn-1,p0为商品初始价格,第一天价格变为p0+p1,记为sum1,第二天为p0+p1+p2,记为sum2,…,最后给你一个k,你可以每次将p0~pn-1中的一个数字加1,最终要使得对所有i(1<=i<=n-1), p i s u m i − 1 < = k % \frac{p_i}{sum_{i-1}} <= k\% sumi1pi<=k%
思路:对于第i天如果不满足 p i s u m i − 1 < = k % \frac{p_i}{sum_{i-1}} <= k\% sumi1pi<=k%,则需要增加 s u m i − 1 sum_{i-1} sumi1,因为增加p1 ~ pi-1可能会让某一天变得不满足条件,让次数再次增加,而直接加到p0上便为最优解

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,n,k;
ll x,sum;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&k);
		scanf("%lld",&sum);
		ll ans= 0 ;
		for(int i = 1;i < n;++i)
		{
			scanf("%lld",&x);
			ll tmp = (100*x+k-1)/k;
			if(sum < tmp)
			{
				ans += tmp-sum;
				sum = tmp;
			}
			sum += x;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

C Longest Simple Cycle

题意:有n条链,每条链由ci个点依次连边组成,标号为1 ~ ci,第i(2 <= i <= n)条链的第1个节点与第i-1条链的第ai个节点连边,第ci个节点与第i-1条链的第bi个节点连边,问这样一个图中最大的简单环大小为多大
思路:首先假设ai<bi,第一条链的a2节点连向第二条链的1号节点,b2节点连向第二条链的c2号节点,中间a2直接一路连边到b2,依次扩展,如果环在第i条链收尾,则会增加长度ci-1,记录个最大值然后继续往下扩展,此时可能是之前的环扩展而来,继续扩展增加长度 a i + 1 − 1 + c i − b i + 1 a_{i+1}-1+c_{i}-b_{i+1} ai+11+cibi+1 也可能从当前链开始,ai+1~bi+1依次连边重新开始扩展,二者取最大值,如果ai+1=bi+1,那么必须从当前链重新开始扩展否则不是简单环

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int t,n;
ll a[MAXN],b[MAXN],c[MAXN];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i = 1;i <= n;++i)
			scanf("%lld",&c[i]);
		for(int i = 1;i <= n;++i)
			scanf("%lld",&a[i]);
		for(int i = 1;i <= n;++i)
			scanf("%lld",&b[i]);
		ll ans = abs(a[2]-b[2]);
		ll tmp = ans + 2;
		for(int i = 2;i < n;++i)
		{
			ans = max(ans,tmp + c[i]-1);
			if(a[i+1] == b[i+1])
				tmp = 2;
			else
				tmp = max(tmp+c[i]-max(a[i+1],b[i+1]) + min(a[i+1],b[i+1])-1,abs(a[i+1]-b[i+1])) + 2;
		}
		ans = max(ans,tmp + c[n]-1);
		printf("%lld\n",ans);
	}
	return 0;
}

D Journey

题意:有n+1座城市标号为0~n,相邻标号的两座城市有一条边,可能往左(i+1向i连边),也可能往右,你从一个城市出发,每走一步所有边的方向反向,可以重复经过同一个城市,问你从每一个城市出发,各自最多能访问多少个城市
思路:首先往一个方向走一步后边反向便能回来,返回后边和初始一样,所以可以分开看往左和往右最多到达多少个城市,现往右走,假设往左的边为0,右为1,则最远到达的必为101010这样交叉出现的边,由1开始,直接从后往前推便好,遇到0则不能往右答案为0,记录下交叉了多少次,遇到1赋值,往左同

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
int t,n,a[MAXN],ans[MAXN];
char s[MAXN];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%s",&n,s);
		for(int i = 0;i < n;++i)
		{
			if(s[i] == 'L')
				a[i] = 0;
			else
				a[i] = 1;
		}
		ans[n] = 0;
		a[n] = a[n-1];
		int tmp = 0;
		for(int i = n-1;i >= 0;--i)
		{
			ans[i] = 0;
			if(a[i+1] != a[i])
				++tmp;
			else
				tmp = 1;
			if(a[i] == 1)
				ans[i] += tmp;
		}
		for(int l = 0,r = n-1;l < r;++l,--r)
			swap(a[l],a[r]);
		a[n] = a[n-1];
		tmp = 0;
		for(int i = n-1;i >= 0;--i)
		{
			if(a[i+1] != a[i])
				++tmp;
			else
				tmp = 1;
			if(a[i] == 0)
				ans[n-i] += tmp;
		}
		for(int i = 0;i <= n;++i)
			printf("%d ",ans[i]+1);
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值