Codeforces Round #764 (Div. 3) A-E题解

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #764 (Div. 3) A-E题解相关的知识,希望对你有一定的参考价值。

A. Plus One on the Subset

就是最大值减去最小值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[55];

void solve()

	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	ll mx = *max_element(a+1,a+1+n);
	ll mn = *min_element(a+1,a+1+n);
	ll res = 0;
	res = mx - mn;
	cout<<res<<'\\n';

int main()

	int t;
	cin>>t;
	while(t--) solve();
	return 0;
  

B. Make AP

a , b , c a,b,c a,b,c三个正整数,将其中一个数乘一个正整数 m m m,问是否能构成等差数列

等差数列性质: 2 b = a + c 2b = a+ c 2b=a+c

所以直接按上述条件进行分类

2 b = a + c 2b = a+ c 2b=a+c时,直接构成等差数列

2 b < a + c 2b < a+ c 2b<a+c时,说明b比较小,需要将乘m,最终能成立的条件是 ( a + c ) % ( 2 b ) = 0 (a+c)\\%(2b)=0 (a+c)%(2b)=0

2 b > a + c 2b > a+ c 2b>a+c时,说明需要将acm,以a为例,则需 m a + c = 2 b ma+c=2b ma+c=2b,则 ( 2 b − c ) % a = 0 (2b-c)\\%a=0 (2bc)%a=0,如果不等于0的话,那么m就为小数,不满足。所以 ( 2 ∗ b − c ) % a , ( 2 ∗ b − a ) % c (2*b-c)\\%a,(2*b-a)\\%c (2bc)%a,(2ba)%c其中之一满足等于0即可.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve()

	ll a,b,c;
	cin>>a>>b>>c;
	if(2*b==a+c) cout<<"YES\\n";
	else
	
		if(2*b < a+c)
		
			if((a+c)%(2*b)==0) cout<<"YES\\n";
			else cout<<"NO\\n";
		
		else 
		
			if((2*b-c)%a!=0 && (2*b-a)%c!=0) cout<<"NO\\n";
			else cout<<"YES\\n";
					
	

int main()

	int t;
	cin>>t;
	while(t--) solve();
	return 0;
  

C. Division by Two and Permutation

n个数,可以对任意一个数做除2下取整操作,问是否能构成一个n的排列

原始的序列中小于等于n的我们不进行操作,因为这些数会包含 比n大的数除2取整得不到的数。
我们使用vis标记一个数是否出现过。

对于其它的没有使用过的数,我们对他们从小到大进行操作,对于每个数,除二取整,一旦得到的数小于等于n且未被标记,就对此进行标记并退出。

如果一个数不断除2,得到的数都已经被标记出现过了,那么这个数等于说是废了,排列一定形不成。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
int a[N];
int n;
bool vis[N];

void solve()

	memset(vis,false,sizeof vis);
	cin>>n;
	vector<int>u;
	for(int i=1;i<=n;i++) 
	
		cin>>a[i];
		if(a[i] <= n && !vis[a[i]]) vis[a[i]] = true;
		else u.push_back(a[i]);
	
	sort(u.begin(),u.end());
	for(auto i : u)
	
		bool is = false;
		int x = i / 2;
		while(x)
		
			if(x <= n && !vis[x])
			
				vis[x] = true;
				is = true;
				break;
			
			x /= 2;
		
		if(!is) 
		
			cout<<"NO\\n";
			return;
		
	
	cout<<"YES\\n";

int main()

	int t;
	cin>>t;
	while(t--) solve();
	return 0;
  

D. Palindromes Coloring

一个字符串,每个字母可以染色可以不染色,字符串一共染有k种颜色,同种颜色之间的字母可以互相交换,要保证一个字符串种同种颜色字母组成的字符串为回文字符串,求字符串中最短回文子串的最长长度。

分析:相同颜色之间的字母可以互相交换,但是呢,颜色是自己指定的,也就是,自己可以随便交换字母的位置,就是自己可以随意安排这些字母了,不用在意原始的字母顺序,只需在意字母出现的次数。

每个颜色要组成一个回文字符串,那么给定的字符串要组成k个回文串。

对于k个回文串,保证最短回文串长度最长,那么就要保证每个回文串分配子母尽可能平均分配,这样最短的回文串的长度才可能尽可能大。

我们统计每个字母出现的次数,每个字母下除2下取整的结果就是每个字母的可组成对数(回文肯定是两边一边一个字母的),求出所有的字母对数的总和。总和除k就是k个回文串分配的最少字母对。

最后肯定是还剩下多余的字母对和字母个数为奇数时剩下的单个字母,这些字母还可以充当回文串最中间的字母。如果这些字母的个数大于等于k,那么回文串长度还可以再加一。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
int cnt[N];

void solve()

	int n,k;
	cin>>n>>k;
	string s;
	cin>>s;
	memset(cnt,0,sizeof cnt);
	for(int i=0;i<s.size();i++)
		cnt[s[i]-'a'] ++;
	int tot1 = 0,tot2 = 0;
	for(int i=0;i<26;i++) tot1 += cnt[i] / 2;
	for(int i=0;i<26;i++) tot2 += cnt[i] % 2;
	int res = tot1 / k * 2;
	if(tot1 % k * 2 + tot2 >= k) res ++;
	cout<<res<<endl;

int main()

	int t;
	cin>>t;
	while(t--) solve();
	return 0;
  

E. Masha-forgetful

给定n个长度为m的数字串,再给一个长度为m的数字串,要求将该数字串拆分成一些部分,保证每部分长度大于等于2,如果每个片段都能在给出的n个数字串中找到的话,就输出每个部分在前面出现的位置区间和出现在第几个数字串中。如果某个部分在前面没有出现,就输出-1.

其实就是求一个字符串拆分成的各部分在前面出现的区间和位置。

一个数字串可以拆分成长度很长的部分,但是任何数字串都可以拆分长度为2和长度为3数字串的组合。根据此性质,我们就可以进行动态规划(因为只有两种情况,拆成长度为2和拆成长度为3)

需要统计长度为2和长度为3的字串出现的位置和区间(使用tuple),vis标记字符串是否出现。
状态表示:
f [ i ] f[i] f[i]:代表前缀长度为i的字符串拆分的部分能够在前n个字符串中找到
状态转移:
f [ i ] = f [ i − k ] f[i] = f[i-k] f[i]=f[ik],k+1是最后一个部分拆分的长度(k代表什么就可以理解了)

转移的时候,一定要注意下标的问题,f[]的下标是从1开始的,字符串下标是从1开始的。
中途需要记录一个p数组,代表转移成功时,前一个转移成功字母的位置,方便从后面往前面回溯。

最后对结果需要倒置一下,回溯的顺序是倒着的,所以需要倒置。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+5;

map<string,bool> vis;
map<string,tuple<int,int,int> >pos;
bool f[N];
int p[N];

void solve()

	memset(p,0,sizeof p);
	memset(f,false,sizeof f);
	int n,m;
	cin>>n>>m;
	//统计
	for(int i=1;i<=n;i++)
	
		string s;
		cin>>s;
		for(int j=0;j<m;j++)
		
			string t;
			t += s[j];
			for(int k=1;k<=2;k++)
			
				if(j + k >= m) break;
				t += s[j+k];
				if(!vis[t])
				
					vis[t] = true;
					pos[t] = make_tuple(j,j+k,i);
				
			
		
	
	
	string s;
	cin>>s;
	//计算
	f[0] = true;
	for(int i=0;i<m;i++)
	
		string t ;
		t += s[i];
		for(int k=1;k<=2;k++)
		
			if(i - k < 0) break;
			t = s[i - k] + t;
			if(vis[t] && f[i-k])
			
				f[i+1] = true;
				p[i+1] = i-k;
				
			//转移成功及时退出,避免下一次又成功转移
			if(f[i+1]) break;
		
	
	vis.clear();//清空,初始化
	if(!f[m])
	
		cout<<"-1\\n";
		return ;
	
	vector<tuple<int,int,int> >res;
	
	for(int i = m;i >= 1;)
	
		int pre = p[i];
		string t = s.substr(pre,i-pre);
		res.push_back(pos[t]);
		i = pre;
	
	cout<<res.size()<<endl;
	reverse(res.begin(),res.end());
	for(auto ans : res)
		cout<<get<0>(ans)+1<<" "<<get<1>(ans)+1<<" "<<get<2>(ans)<<endl; 


int main()

	int t;
	cin>>t;
	while(t--) solve();
	return 0;
  

往期优质文章推荐

领取大量学习资源

以上是关于Codeforces Round #764 (Div. 3) A-E题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #764 (Div. 3)

Codeforces Round #764 (Div. 3) A-E题解

Codeforces Round #436 E. Fire(背包dp+输出路径)

Codeforces Round #394 (Div. 2)

Codeforces Round #395 C. Timofey and a tree

[ACM]Codeforces Round #534 (Div. 2)