Educational Codeforces Round 151 (Rated for Div. 2) A~D

文章详细解析了四道编程比赛中的题目,包括ForbiddenInteger、ComeTogether、StrongPassword和RatingSystem,涉及数字逻辑、路径优化和字符串处理等算法问题,提供了解题思路和代码实现,旨在提升编程解决问题的能力。

比赛链接:Dashboard - Educational Codeforces Round 151 (Rated for Div. 2) - Codeforces

目录:

A. Forbidden Integer

B. Come Together

C. Strong Password

D. Rating System


A. Forbidden Integer

题意:给你三个整数n,k,x,你可以使用1~k中除x以外的任意数字,并且能使用无数次,问你能不能从中选出拼出n的数字。

 思路:若x不为1则输出n个1即可,若x为1,只有两种情况是拼不出n的:

①n为奇数且k=2,这说明了我们只能选择数字2,而数字2是拼不出奇数的。

②k等于1,此时我们什么数字都选不了,自然是拼不出n。

排除no的答案后,n为偶数的情况可以用n/2个2拼出,n奇数且n大于等于3的情况可以由n/2-1个2加上一个3来拼出。

代码:

void solve() {
	int n,k,x;
	cin>>n>>k>>x;
	if(x!=1) {
		cout<<"YES"<<endl;
		cout<<n<<endl;
		FOR(1,n) cout<<1<<" \n"[i==n];
	} 
	else if((n%2&&k==2)||k==1) cout<<"NO\n";
	else {
		cout<<"YES"<<endl;
		cout<<n/2<<endl;
		FOR(1,n/2) cout<<2<<" ";
		cout<<2+(n%2)<<endl;
	}
}

B. Come Together

题意:两个人同时从同一地点A出发,前往两个位置B和C,且分别采用步数最短的走法,问你能重叠的路径最多有多少个。

思路:分类讨论,若B点的横坐标和C点的横坐标相对于A点的纵坐标在同一侧,则对于答案的贡献为B点和C点与A的横坐标距离的较小值,也就是“公共横坐标路径”,公共纵坐标路径的贡献的计算同理。

代码:

void solve() {
	int ax,ay,bx,by,cx,cy,f1,f2,ans=0;
	cin>>ax>>ay>>bx>>by>>cx>>cy;
	int x1=abs(ay-by),y1=abs(ay-cy);
	int x2=abs(ax-bx),y2=abs(ax-cx);
	if((by>ay)==(cy>ay))ans+=min(x1,y1);
	if((bx>ax)==(cx>ax))ans+=min(x2,y2);
	cout<<ans+1<<endl;
}

C. Strong Password

题意:给定一个仅包含数字的字符串 s ,然后再给定 m 个区间 [li,ri](1<=i<=m),数字第i个位必须在这第i个区间的范围内,问能否从这 m 个区间中分别取出一个合法数字,拼成字符串后其不是字符串 s 的子序列。

思路:首先,对于每一位上数字的数字k,我们从它的范围[li,ri]遍历一遍,在遍历的过程中,若k在字符串中存在,则最优的选法是数字k在未被“删”去的字符串中第一次出现的相同数字的靠后位置。

例如,我们可以选择数字有:1,2,3,字符串s是111222333,我们的最优选择则是数字3,因为选了数字3,子序列的开头必须从标红数字开始——111222333,相当于把这个3前面的数字“111222”都“删”了,不用再考虑了,所以自然是删的越多越好。若我们选择了数字2,则子序列从111222333开始,“删”的数字少了,肯定不如选择数字3。

 若字符串s中未被“删”去的序列中找不到k,则直接输出yes。

代码:

void solve() {
	string s,t1,t2;
	int m,k=0;
	cin>>s>>m>>t1>>t2;
	FOR(0,m-1) {
		int maxx = 0;
		for (char j = t1[i]; j <= t2[i]; ++j) {
			int tmp = s.find(j, k);
			if (tmp>=s.size()) {
				cout<<"YES"<<endl;
				return;
			}
			maxx=max(maxx,tmp+1);
		}
		k = maxx;
	}
	cout<<"NO"<<endl;
}

D. Rating System

题意:找任意一个可能的值 k ,使得 n 轮比赛后的得分是最大的(得分为累加)。其中需要评分先到达 k,才会使得评分低于 k 后会保持k不变。

思路:可以得出的一个结论是:k一定等于某个前缀。因为若要使得k有意义,则一定要有一个前缀大于等于k,才会使得k有作用,也就是说k小于等于某个前缀,它才有作用。那么不妨让k取最大也就是等于某个前缀,然后枚举每个k作为每个前缀时的最终答案,枚举的答案为前缀加上最大的后缀。

为什么是最大的后缀呢?因为我们在枚举第i个位置作为前缀时,后面i+1~n的位置的负数贡献对于答案是没有意义的,贡献都是0。只有后缀为正数贡献才能使得最终的n发生改变,改变的量为i+1~n中最大的后缀。(注意i=0的情况也要枚举)

代码:

void solve() {
	int n,summ=0,maxx=0,ans=0;
	cin>>n;
	maxh[n+1]=0;
	FOR(1,n) {
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
	ROF(n,1) {
		summ+=a[i];
		maxh[i]=max(maxh[i+1],summ);
	}
	FOR(0,n) {
		int k=sum[i]+maxh[i+1];
		if(k>maxx) {
			maxx=k;
			ans=sum[i];
		}
	}
	cout<<ans<<endl;
}

### Codeforces Educational Round 168 Div. 2 Problem D 解析 #### 题目概述 题目描述涉及给定一个长度为 n 的数组 a 和整数 k,目标是在不超过 k 次操作的情况下使数组中的所有元素相等。每次操作可以选择任意数量的元素并将其增加或减少 1。 为了实现这一目标,需要找到一种策略来最小化所需的操作次数,使得最终所有的数组元素都相同[^1]。 #### 关键思路 核心在于理解到最优解通常是将所有元素变为中位数值。这是因为对于任何一组数字来说,调整至中位数所需的总移动量是最少的。具体而言: - 如果 n 是奇数,则存在唯一的中间值作为最佳目标; - 若 n 为偶数,则两个可能的目标分别是位于中心位置相邻的一对平均值之一; 考虑到最多可以执行 k 次修改动作,在某些情况下即使不是严格意义上的“中位数”,也可以通过适当选取接近它的其他值达到目的,只要满足条件即可。 #### 实现方法 以下是解决该问题的一种算法框架: ```cpp #include <bits/stdc++..h> using namespace std; int main() { int t; cin >> t; while (t--) { long long n, k; cin >> n >> k; vector<long long> a(n); for(auto &i : a) cin >> i; sort(a.begin(), a.end()); map<int,int> m; // 记录每个差异数出现频率 for(int i=0; i<n-1; ++i){ if(abs(a[i]-a[i+1])!=0)m[abs(a[i]-a[i+1])]++; } auto it=m.rbegin(); bool flag=true; while(k && !m.empty()){ if(it->second<=k){ k-=it->second; m.erase((++it).base()); }else{ cout << "NO\n"; flag=false;break; } it=m.rbegin(); } if(flag || m.size()==0)cout<<"YES\n"; } } ``` 此代码片段实现了上述逻辑的一部分,即尝试尽可能多地消除差异最大的一对元素之间的差距直到无法继续为止。需要注意的是这段代码并不完全适用于所有情况下的直接提交测试,而是提供了一个基本的方向指引。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值