Codeforces Round #849 (Div. 4)(A-G2)

本文介绍了若干算法竞赛题目,包括基于字符串的简单匹配,遵循方向的操作模拟,以及涉及数组更新和查询的问题。同时,还讨论了如何利用树状数组解决区间更新和点查询问题,并分析了不同版本的传送器问题及其解决方案。

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

目录

A. Codeforces Checking

B. Following Directions

C. Prepend and Append

D. Distinct Split

E. Negatives and Positives

F. Range Update Point Query

G1. Teleporters (Easy Version)

G2. Teleporters (Hard Version)


A. Codeforces Checking

题意:给你一个字符问这个字符是不是属于“ codeforces”中的一个,是就输出“YES”,否则输出“NO”。

思路:手速题,可以直接遍历,如果存在相等就直接输出YES,遍历完如果都没有就输出NO。

代码:

void slove( )
{
	char s;
	cin>>s;
	string str="codeforces";
	bool st=0;
	for(int i =0;i<10;i++)
	if(s==str[i])st=1;
	if(st)cout<<"YES\n";
	else cout<<"NO\n";
}

B. Following Directions

题意:给你一系列的操作,问在起始点(0,0)的你能不能经过这些操作经过点(1,1),如果能输出YES,否则输出NO。

思路:每个字符判断一下,然后如果走到目标点了就直接输出结果,否则就输出NO。

void slove( )
{
	int t;
	sc_int(n);
	cin>>s+1;
	int x=0,y=0;
	bool st=0;
	for(int i =1;i<=n;i++)
	{
		if(s[i]=='L')x--;
		if(s[i]=='R')x++;
		if(s[i]=='U')y++;
		if(s[i]=='D')y--;
		if(x==1&&y==1)st=1;
	}
	if(st)cout<<"YES\n";
	else cout<<"NO\n";
}

C. Prepend and Append

题意:有一个字符串a,他可以进行操作任意次操作(a的顶部+'0'并且a的尾部+'1'或者a的顶部+'1'并且a的尾部+'0'),现在给你操作后的字符串A,问初始字符串的长度最短是多少。

思路:直接暴力,如果可以缩短就缩,直到缩短不了为止。

代码:

void slove( )
{
	int t;
	sc_int(n);
	cin>>s+1;
	int ans=0;
	for(int i =1,j=n;i<=j;i++,j--)
	{
		if((s[i]=='0'&&s[j]=='1')||(s[i]=='1'&&s[j]=='0'))
		ans++;
		else break;
	}
	cout<<n-ans*2;
	cout<<endl;
}

D. Distinct Split

题意:定义一个字符串f(a)=字符串内不同的字符的个数,现在给你一个字符串a,让你把a拆成两部分bc,问你f(b)+f(c) 的最大值是多少。

思路:三次循环,第一次遍历前i位构成的字符串的f(a)是多少,第二次遍历后i位构成的字符串的f(b)  是多少,第三次每一位都遍历一下,然后取最大值就可以了。

代码:

void slove( )
{
	int t;
	sc_int(n);
	cin>>s+1;
	map<int,int>q,qq,p,pp;
	for(int i =1;i<=n;i++)
	{	
		if(!q[s[i]])qq[i]=qq[i-1]+1;
		else qq[i]=qq[i-1];
		q[s[i]]=1;
	}
	
	for(int i =n;i>=1;i--)
	{	
		if(!p[s[i]])pp[i]=pp[i+1]+1;
		else pp[i]=pp[i+1];
		p[s[i]]=1;
	}	
	int res=0;
	for(int i =1;i<=n;i++)
	{
		res=max(res,qq[i]+pp[i+1]);
	}
	cout<<res;
	cout<<endl;
}

E. Negatives and Positives

题意:给你一个数组n,然后你可以在下标i(1<=i<n)使,(可以执行任意次)然后问你最大的数组和是多少。

思路:经过几次的模拟我们可以发现这个操作的本质就是使任意两个数符号变成相反位,那么对于负数是偶数个,全部加上就可以了:如果是奇数个,那就看最大的负数和最小的正数的绝对值哪个大哪个小然后看换不换就可以了。具体操作可以把负数全部变成正数全部加起来然后排序一下,如果是奇数个负数最小的就是我们要删除的数。

代码:

void solve() {
	int n,sum=0,ans=0;
	cin>>n;
	FOR(1,n) {
		cin>>a[i];
		if(a[i]<0)sum++,a[i]=-a[i];
		ans+=a[i];
	}
	sort(a+1,a+n+1);
	if(sum%2)ans-=2*a[1];
	cout<<ans<<endl;
}

F. Range Update Point Query

题意:给你一个长度为n的数组,还有两种操作:

1.给你l,r使l,r范围内的元素等于他的每一位的数字之和

2.给你一个x(x<n),让你输出x位置对应的元素。

思路:典型的树状数组(线段树),直接写就可以了。(我这里的k是用来存储某个点当前已经进行了几次操作,因为不会删除就只好这么写了qwq)

代码:



#include<cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include<vector>
#include<queue>
#include<map>
#define sc_int(x) scanf("%d", &x)
#define sc_ll(x) scanf("%lld", &x)
#define pr_ll(x) printf("%lld", x)
#define pr_ll_n(x) printf("%lld\n", x)
#define pr_int_n(x) printf("%d\n", x)
#define ll long long 
using namespace std;

const int N=1000000+100;
int n ,m,h;
int s[N],k[N],now[N];


int lowbit(int x){return x&(-x);}

void updata(int x,int k){
	for(int i =x;i<=n;i+=lowbit(i))
	now[i]+=k;
}

int getsum(int k)
{
	int res=0;
	for(int i =k;i;i-=lowbit(i))
	{
		res+=now[i];
	}
	return res;
}


int call(int x)
{
	int sum=0;
	while(x)
	{
		sum+=x%10;
		x/=10;
	}
	return sum;
}

void slove( )
{
	int t;
	sc_int(n),sc_int(m);

	for(int i =1;i<=n;i++) sc_int(s[i]);
	
	while(m--)
	{
		int x,a,b,c;
		cin>>x;
		if(x==1){
			sc_int(a),sc_int(b);
			updata(a,1),updata(b+1,-1);
		}
		else{
			sc_int(c);
			int x=getsum(c);
			for(int i =k[c];i<x&&s[c]!=call(s[c]);i++)
			{
				s[c]=call(s[c]);
			}
			printf("%d\n",s[c]);
			k[c]=x;			
		}
	}

	for(int i =1;i<=n;i++){
		now[i]=0;
		k[i]=0;
	}
}

int main()
{
	int t;
	sc_int(t);
	while(t--)
	slove();


	return 0;
}

G1. Teleporters (Easy Version)

题意:考虑数轴上的点 ,,(0,1,…,n) 在 ,,1,2,…,n 的每个点上都有一个传送器。在第 i 点,你可以这样做:

向左移动一个单位:花费 1 枚硬币。
向右移动一个单位:花费 1 枚硬币。
在i点使用传送器(如果存在的话):它需要 a[i] 金币。因此,你可以传送到点 0 。一旦你使用了传送器,你就不能再使用了。
你有 c 个硬币,从 0 点开始,最多能使用多少个传送器?

 思路:直接把每个启动传送器需要的代价计算一下,然后sort排序一下就可以了。

代码:

void slove( )
{
	int t;
	sc_int(n);
	cin>>m;
	for(int i =1;i<=n;i++)
	{
		cin>>s[i];
		k[i]=i+s[i];
	}
	sort(k+1,k+1+n);
	int sum=0;
	for(int i =1;i<=n;i++)
	{
		if(m>=k[i])
		{
			sum++;
			m-=k[i];
		}
		else break;
	}
	cout<<sum;
 
	cout<<endl;
}

G2. Teleporters (Hard Version)

题意:考虑数轴上的点 ,,(0,1,…,n) 在 ,,1,2,…,n 的每个点上都有一个传送器。在第 i 点,你可以这样做:

向左移动一个单位:花费 1 枚硬币。
向右移动一个单位:花费 1 枚硬币。
在i点使用传送器(如果存在的话):它需要 a[i] 金币。因此,你可以传送到点 0 ,或者传送到点n+1。一旦你使用了传送器,你就不能再使用了。
你有 c 个硬币,从 0 点开始,最多能使用多少个传送器?

思路:对于每个传送器,我们花费的代价有两个:a[i]+i或者a[i]+n-i+1。若不考虑起始点为0的话,只需要将这两个花费取min然后排序即可。但是因为起始点为0,所以我们所选的第一个传送器它的花费必然是a[i]+i,因此我们枚举所有传送器作为第一个传送器的情况,然后用二分查找去找能够使用到的传送器的最大数量,但是这里有可能包括我们第一个传送器的价值,那么我们进行大小的比较,详情可以看代码。

代码:

#include<cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include<vector>
#include<queue>
#include<map>
#define sc_int(x) scanf("%d", &x)
#define sc_ll(x) scanf("%lld", &x)
#define pr_ll(x) printf("%lld", x)
#define pr_ll_n(x) printf("%lld\n", x)
#define pr_int_n(x) printf("%d\n", x)
#define ll long long 
using namespace std;

const int N=1000000+100;
int n ,m,h;
ll s[N],k[N],cnt[N];

int find(ll x)
{
		int l=0,r=n;
		while(r>l)
		{
			int mid=l+r+1>>1;
			if(cnt[mid]<=x)l=mid;
			else r=mid-1;
		}
		return l;
}

void slove( )
{
	int t;
	sc_int(n),sc_int(m);
	map<int,int>q;
	for(int i =1;i<=n;i++){
	sc_int(s[i]);
	k[i]=min(s[i]+i,s[i]+n-i+1);
	q[i]=k[i];//第i个人需要的最小的花费
	}	

	sort(k+1,k+1+n);
	for(int i =1;i<=n;i++)cnt[i]=cnt[i-1]+k[i];
	
	int sum=0;
	for(int i =1;i<=n;i++)
	{
		int res=m;
		if(s[i]+i>res){
			continue;
		}
		res-=(s[i]+i);
		int si=find(res);
		if(k[si]<q[i])//如果最小花费大于第k个人的花费那么就说明一定用不到这种情况
		sum=max(sum,si+1);
		else sum=max(sum,find(res+q[i]));//否则就会用到这个机器,那么就加上他然后再查找一
        //边即可
		
	}
	cout<<sum;



	cout<<endl;
}

int main()
{
	int t;
	sc_int(t);
	while(t--)
	slove();


	return 0;
}

### 关于Codeforces Round 971 (Div. 4)比赛题目及解析 #### A-G1题解概述 对于Codeforces Round 971 (Div. 4),该轮次的比赛涵盖了多个难度级别的编程挑战,旨在测试参赛者的算法思维能力和编码技巧。其中,A至G1的题目设计覆盖了基础数据结构操作、贪心策略应用以及动态规划等多个方面。 #### G2. Yunli’s Subarray Queries (Hard Version) 具体到G2这道难题目,其背景设定在一个由n个节点构成的无向图环境中,此图恰好拥有\( n-1 \)条带权重的边,每一边连接着两个连续编号的顶点,并且初始状态下每个顶点都放置了一个与其自身编号相匹配的小球[^1]。问题的核心在于计算一种最优方案下的总成本——即通过调整各小球的位置让它们不再位于原本对应的顶点之上;每一次位置交换都需要支付相应路径上的代价(即边的权重),而目标就是找到能够满足上述条件的同时使总的迁移费用达到最低的方法。 针对此类涉及最短路径求解的问题,通常采用广度优先搜索(BFS)或迪杰斯特拉(Dijkstra&#39;s Algorithm)等经典图论算法来进行处理。然而,在本题特殊条件下,则更倾向于利用差分数组配合线段树/树状数组来高效解决区间更新与查询的需求,从而快速响应多次修改后的即时状态变化并给出正确解答[^2]。 ```cpp #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int a[N], b[N]; long long sum[N << 2]; void push_up(int rt){ sum[rt] = min(sum[rt<<1],sum[rt<<1|1]); } // build, update and query functions omitted for brevity... int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,q,x,y,z; cin >> n >> q; // initialization code here... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值