Educational Codeforces Round 103 (Rated for Div. 2)A-D题解

A. K-divisible Sum
题意:
给出两个整数n和k,要你构造一个由 n 个正整數 a1,a2,…,an 组成的阵列,使 (a1+a2+⋯+an) 之和被 k 整除,且 a 中的最大元素是最小的。输出a中的最大可能元素是多少
思路:
为了使构成的数组的最大值最小,只需要让数组中的元素尽可能相同即让数字都等于n / k,当n / k无法整除时,那么最大值就是 n / k向上取整(ceil)。但是,当n>k时便无法满足,这个时候我们需要让k倍增,使k刚好大于等于n,最终输出答案即可。要注意的是用朴素得for循环倍增会超时
AC代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long t,a,b;
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld",&a,&b);
		if(a > b)
		{
			if(a%b==0) b = a;
			else//k倍增
			{
				long long k = a/b;
				b = b*(k+1);
			}
		} 
		if(b%a==0) printf("%lld\n",b/a);
		if(b%a!=0) printf("%lld\n",b/a+1);
	}
	return 0; 
}

B. Inflation
题意:
给你一个长度为 n 的数列和一个 k ,可以对数列中每一个数加上一个值,要求每个数与其左侧的数之和的比小于等于 k %,输出加上值总和的最小值
思路:
如果某一个点不符合要求,只需要考虑前面最少要加多少即可,不需要考虑加的位置,因为可以都加在 p0 位置。要注意的是在做判断时尽量用乘法代替除法,以减少不必要的精度问题
AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int INF =  0x3f3f3f3f;
long long p[maxn];
long long pre[maxn];
int main()
{
	int t,n,k;
	cin >> t;
	while(t--)
	{
		cin >> n >> k;
		memset(pre,0,sizeof(pre));
		for(int i = 1;i <= n;i++)
		{
			cin >> p[i];
			pre[i+1] = pre[i]+p[i];
		}
		long long ans = 0;
		for(int i = n;i > 1;i--)
		{
			if(p[i]*100 > pre[i]*k)
			{
				long long d = p[i]*100/k-pre[i];
				if((pre[i]+d)*k<p[i]*100) d+=1;
				ans += d;
			}
			pre[i-1] += ans;
		}
		cout << ans << endl;
	}
	return 0;
}

C. Longest Simple Cycle
题意:
有 n 条链,ai 表示第 i 条链的第一个点与前一条链所连接的点的编号,bi 表示第 i 条链的最后一个点与前一条链所连接的点的编号,ci 表示第 i 条链的长度(共有几个节点)。求节点数最多的环,并输出其节点数。
思路:
从最左边的链遍历,可以遇到的环有两种
1.连接下一链的两节点为同一点,那一点代表当前环结束
2.连接下一链的两节点为不同点,那两点之间的边为环最后的边
我们只需要对每一条链上的两个节点进行判断,再利用贪心算法就能得到有最多边的环
AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
const int INF  = 0x3f3f3f3f;
int a[maxn],b[maxn],c[maxn];
int main()
{
	int t,n;
	cin >> t;
	while(t--)
	{
		cin >> n;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		for(int i = 1;i <= n;i++) cin >> c[i];
		for(int i = 1;i <= n;i++) cin >> a[i];
		for(int i = 1;i <= n;i++) cin >> b[i];
		for(int i = 1;i <= n;i++) if(a[i]>b[i]) swap(a[i],b[i]);//保证上节点为较小的点 
		long long sum = b[2]-a[2];//第一条链 
		long long ans = 0;
		for(int i = 2;i<=n;i++)
		{
			sum+=2;//链接下一条链的两边 
			if(a[i+1]==b[i+1])//出现了第一种环 
			{
				ans = max(ans,sum+c[i]-1);
				sum = 0;
				continue;
			}
			ans = max(ans,sum+c[i]-1);
			if(b[i+1]-a[i+1]>sum+c[i]-1-(b[i+1]-a[i+1]))sum=b[i+1]-a[i+1];//出现了第二种环 
			else	sum+=c[i]-1-(b[i+1]-a[i+1]);
			ans = max(ans,sum);
		}
		cout << ans << endl;
	}
	return 0;
}

D. Journey
题意:
有n+1个城市,编号从0到n,n条道路连接这些城市,第i条道路连接城市i-1和i(i∈[1,n])。
每条道路都有一个方向。如果第i个字符是L,则表示第i条路最初是从城市i到城市i-1,否则是从城市i-1到城市i。道路的方向每天变换一次。
每天,旅行者必须使用其中一条道路从他们目前所在的城市到邻近的城市。
计算如果旅行者从城市i开始,在一次旅行中最多可以访问多少个不同的城市。
思路:
因为每天道路都会变换一次方向,所以只有下一条路与当前路方向不同我们才有可能一直走下去,并且每次回到原点时所有路的方向和初始值一样
所以对于每个点,所能到达的范围就是一直往左走加上一直往右走的最远距离
预处理出相邻不同的前缀 f 和后缀 g 就可以
AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10; 
char s[N];
int T, n, f[N], g[N];
int main() 
{
    cin >> T;
    while (T--) 
	{
        cin >> n;
        scanf("%s", s + 1);
        f[1] = 1;//前缀和 
        for (int i = 2;i <= n;i++) f[i] = (s[i] == s[i - 1]) ? 1 : f[i - 1] + 1;
        g[n] = 1;//后缀和 
        for (int i = n - 1;i >= 1;i--) g[i] = (s[i] == s[i + 1]) ? 1 : g[i + 1] + 1;
        for (int i = 1;i <= n + 1;i++) 
		{
            int ans = 1;
            if (i - 1 >= 1 and s[i - 1] == 'L') ans += f[i - 1];//向右走 
            if (i <= n and s[i] == 'R') ans += g[i];//向左走 
            printf("%d%c", ans, " \n"[i == n + 1]);
        }
    }
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

温柔说给风

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值