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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值