codeforce第874轮(div3)

文章提供了五道编程竞赛题目,涉及字符串的链接、数组分配优化、奇偶数序列构造、数组反转和无向图的环与边的判断。解题策略包括利用哈希表去重、排序优化分配以及图的遍历寻找环和边的数量。

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

地址:codeforce第84轮(div3)

A:

题目的意思是:给定我们一堆包含两个字符的字符串,字符串a和字符串b只要a的后一个字母和b的前一个字母相等即可链接,现在给出最后链接好的字符串,问我们最少能用多少个形如a和b的字符串可以链接;

实际上就是问我们,用多少个包含两个字符的字符串可以构造出答案,可以直接把所有情况写出来,去重即可;

这里可以直接用set去重,你也可以用map,反正哈希表基本都可以

代码如下:

#include<iostream>
#include<set>
using namespace std;
set<string> a;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		a.clear();
		int n;
		string arr;
		cin>>n;
		cin>>arr;
//		cout<<arr<<endl;
		for(int i=1;i<arr.size();i++)
		{
			string k="";
			k+=arr[i-1];
			k+=arr[i];
//			cout<<k<<endl;
			a.insert(k);
		}
		cout<<a.size()<<endl;
	}
 
} 

B:

b题乍一看我们需要找到一个b数组的一个序列,使得a和b的差值能够小于k;

这里我们考虑暴力写法,如果暴力的话我们需要枚举所有情况,因为b的某个数分配给a的某个数之后可能造成a的另一个数得不到分配,这是可能存在的;比如a={3,7},b={8,1},k=5,第一次选择会把8分给3,但是接下来1不能分配给7,但是我们发现把1分给3,把8分给3是可以的;

所以这道题到这里的分析大家也就看出来了;

因为我们保证题目有解,所有我们把a排序之后,把b排序之后,如果bi+1能分配给ai,那么bi一定能分配给ai。前面情况一样,这样我们就得到了一种最优算法,虽然答案不唯一,但是这种情况很好写。

开个struct,一个变量存a的值,一个存位置,进行a和b的排序之后,再根据结构体位置信息把b按照顺序输出,我这里是开了一个数组再存了一次。

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct ST
{
    int k;
    int si;
}a[100010];
int ans[100010];
int b[100010];
 
int cmp(ST a,ST b)
{
	return a.k<b.k;
}
 
int main()
{
	int t,m;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i].k;
			a[i].si=i;
		}
		for(int i=1;i<=n;i++)
		{
			cin>>b[i];
		}
		sort(a+1,a+n+1,cmp);
		sort(b+1,b+n+1);
		for(int i=1;i<=n;i++)
		{
			ans[a[i].si]=b[i];
		}
		for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
		cout<<endl;
	}
}

C:

首先题目让我们构造出全奇数或者全偶数序列,这个时候我们就要考虑给我们的序列的分布情况,首先全是奇数和全是偶数肯定是有答案的,直接输出YES,这里我们思考有奇数和有偶数的情况,我们思考能否构造出偶数数列;

显而易见这是不可能的,因为奇数减奇数为偶数,你可以用大的奇数减小的奇数得到偶数,但是会剩下最后一个最小的奇数没法减去,所以可以思考构造奇数序列,这里我们发现奇数序列只需要用偶数减去最小的奇数就可以构造。所以不成立的情况就是,存在一个偶数小于最小的奇数。

直接进行遍历,存下奇数个数,偶数个数,奇数最小值,偶数最小值,当偶数最小值小于奇数最小值一定无解即可;

代码:

#include<iostream>
 
using namespace std;
 
int arr[200010];
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,ji=0x3f3f3f3f,ou=0x3f3f3f3f,inj=0,ino=0;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			int k;
			cin>>k;
			if(k%2) inj++,ji=min(k,ji);
			else ino++,ou=min(ou,k);
		}
		if(!inj||!ino) cout<<"YES"<<endl;
		else 
		{
			if(ou<ji) cout<<"NO"<<endl;
			else cout<<"YES"<<endl;
		}
		
	}
}

D:

这道题目需要好好思考一下,题目告诉我们需要找到其中一个区间进行反转,再把前后交换得到答案,这里我们想,如何才能使字典序最大呢?

肯定是要先把最大的数字放在最前面,那么根据这个情况,我们能找到两种解决方案,一种是找到最大数字的前一个,让他变成r位置,遍历l位置,模拟reverse过程计算一个答案。还有一种情况就是选择最大值,这个时候只会在最大值在最后一个数的时候成立,因为如果最大数不在最后一个位置,你选择以后交换前后值得时候肯定有数字在最大值前面,所以这个不可以。

还有一种情况是最大值在最前面,因为我们进行选择的时候,反转的数组一定在最大值前面,所以当最大在第一个,你的数组是一定会把最大值调到后面的,这个时候我们就要考虑次最大值了。

我们可以选择次最大值,这样次最大值进行选择的时候还是会把最大值移位,并且在次最大值排最前面的选择里,一定可以达到最大;

写法就是模拟上述这个过程

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
 
int n,ma=0,si=0;
const int N=2010;
int pd[N],arr[N],b[N];
int ans[N];
 
int rever(int l,int r)
{
	for(int i=l,j=r;i<j;i++,j--)
	{
		swap(b[i],b[j]);
	}
}
int cun(int l,int r)
{
	int o=1;
	for(int i=r;i<=n;i++) pd[o++]=b[i];
	for(int i=l+1;i<=r-1;i++) pd[o++]=b[i];
	for(int i=1;i<=l;i++) pd[o++]=b[i];
}
 
int pdsw()
{
	int flag=0;
	for(int i=1;i<=n;i++)
	{
		if(pd[i]>ans[i])
		{
			flag=1;
			break;
		}
		else if(pd[i]<ans[i])
		{
			flag=0;
			break;
		}
	}
	if(flag)
	{
		for(int i=1;i<=n;i++) ans[i]=pd[i];
	}
}
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		memset(ans,0,sizeof(ans));
		ma=0,si=0;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>arr[i];
			if(arr[i]>ma) ma=arr[i],si=i;
		}
		if(si==1)
		{
			for(int i=1;i<=n;i++)
			{
				if(arr[i]==ma-1) 
				{
					si=i;
					break;
				}
			}
		}
		for(int i=si-1;i>=1;i--) 
		{
//			cout<<i<<' '<<si-1<<endl;
			for(int j=1;j<=n;j++) b[j]=arr[j];
			
			rever(i,si-1);
			
//			for(int j=1;j<=n;j++) cout<<b[j]<<' ';
//			cout<<endl;
			
			cun(i-1,si);
			pdsw();
		}
		for(int i=si;i>=1;i--) 
		{
//			cout<<i<<' '<<si<<endl;
			for(int j=1;j<=n;j++) b[j]=arr[j];
			
			rever(i,si);
			
//			for(int j=1;j<=n;j++) cout<<b[j]<<' ';
//			cout<<endl;
			
			cun(i-1,si+1);
			pdsw();
		}
		for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
		cout<<endl;
	}
}

E:

这道题目有很强的思维性。

我们首先考虑,每个点只知道他的一个邻居,不知道另一个邻居,这样我们需要查找到最大的和最小的围圈跳舞的人是多少。我们把这个点和他们的邻居连起来,我们会发现有些成环了,而有些没有成环却成边。

如果你多测几组样例很容易就能发现一个问题,一个点不可能和3个及以上点相连,因为那样会造成邻居错误,所以当某一条链成环,她肯定会绕回去。而其他情况也只会成一条竹子型的边,我们下边都简称边。

一个环是一种情况,所有边最小可以成一个环也可以没有,最大每一条边连一个环,边数就等于环数。

我们如何找成边和成环的情况呢?

首先可以用无向图来做,用无向图来存的话,成环说明这条边至少有两个出边,成边说明有一个点只有一条边,可以直接判断不是上一个节点的话,没有节点了,就是边,如果还有并且重复了就是环。

也可以直接从某一个点进入,把这条边或者环所有点存进去,左后判断,只要有一个点只有一条出边就是错误。。

这样我们无论根据上述那种方法都可以计算出来;

这里我使用的是第二种方法;

代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
using namespace std;
 
typedef long long LL;
const int N=200010;
 
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;cin>>n;
		vector<set<int>> g(n);
		vector<int> a(n);
		vector<int> d(n);
		for(int i=0;i<n;i++)
		{
			cin>>a[i];
			a[i]--;
			g[i].insert(a[i]);
			g[a[i]].insert(i);
		}
		
		for(int i=0;i<n;i++) d[i]=g[i].size(); 
		
		int ba=0,cir=0;
		vector<int> vis(n);
		for(int i=0;i<n;i++)
		{
			if(!vis[i])
			{
				queue<int> q;
				q.push(i);
				vis[i]=1;
				vector<int> ans = {i};
				
				while(!q.empty())
				{
					int u=q.front();
					q.pop();
					for(auto v:g[u])
					{
						if(!vis[v])
						{
							vis[v]=1;
							q.push(v);
							ans.push_back(v);
						}
					}
				}
				
				int bam=0;
				for(auto it:ans)
				{
					if(d[it]==1)
					{
						bam=1;
						break;
					}
				}
				if(bam) ba++;
				else cir++; 
			}
		}
		cout<<cir+min(1,ba)<<' '<<cir+ba<<endl;
	}
	
}

### Codeforces Problem or Contest 998 Information For the specific details on Codeforces problem or contest numbered 998, direct references were not provided within the available citations. However, based on similar structures observed in other contests such as those described where configurations often include constraints like `n` representing numbers of elements with defined ranges[^1], it can be inferred that contest or problem 998 would follow a comparable format. Typically, each Codeforces contest includes several problems labeled from A to F or beyond depending on the round size. Each problem comes with its own set of rules, input/output formats, and constraint descriptions. For instance, some problems specify conditions involving integer inputs for calculations or logical deductions, while others might involve more complex algorithms or data processing tasks[^3]. To find detailed information regarding contest or problem 998 specifically: - Visit the official Codeforces website. - Navigate through past contests until reaching contest 998. - Review individual problem statements under this contest for precise requirements and examples. Additionally, competitive programming platforms usually provide comprehensive documentation alongside community discussions which serve valuable resources when exploring particular challenges or learning algorithmic solutions[^2]. ```cpp // Example C++ code snippet demonstrating how contestants interact with input/output during competitions #include <iostream> using namespace std; int main() { int n; cin >> n; // Process according to problem statement specifics } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值