Codeforces Round #767 (Div. 2) A~D

Codeforces Round #767 (Div. 2) A~D

A

题意: 多组数据,电脑有一个初始内存\(k\),下面有\(n\)款软件,每款软件在安装时会暂时消耗你\(a[i]\)的内存,安装好后会永久增加你\(b[i]\)的内存,求最后电脑的内存最大能有多少

Sol: 对于一款软件,如果当前电脑内存够暂时安装它,那么安装必然是最优方案,因此把软件按\(a[i]\)排序,当\(k>=a[i]\)时,加上\(b[i]\)即为最优结果

Code:

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

struct node {
	int x,y;
	bool operator < (const node &a) const {
		return x<a.x;
	}
}t[N];

int T,n,k;

int main() {
	cin>>T;
	while(T--) {
		cin>>n>>k;
		for (int i=1;i<=n;i++) cin>>t[i].x;
		for (int i=1;i<=n;i++) cin>>t[i].y;
		sort(t+1,t+1+n);
		for (int i=1;i<=n;i++) {
			if(k>=t[i].x) k+=t[i].y;
		}cout<<k<<endl;
	}
}

B

题意: 多组数据,给定一个初始区间\([l,r]\),形成一个集合\(S[l,l+1,...,r-1,r]\),每次从集合中任意选取两个数,删掉这两个数后将它们的乘积加入集合\(S\),求这样操作\(k\)次后,集合的最大公约数\(gcd(S)\)能否大于1

Sol: 首先看到这道题就想到\(gcd(x,x+1)=1\) (当然最后没用)

我们知道最后想让\(gcd(S)>1\)最小的公约数就是2,稍微想一下就知道将所有数质因数分解,2一定是出现次数最多的数.
因此想让操作次数尽可能少,最后一定是\(gcd(S)=2\),那么令集合只剩偶数即可,每一次操作我们可以令一个奇数\(\times\)一个偶数,就可以消除一个奇数,这样操作次数就是整个集合中奇数的个数\(cnt\)

最后判断一下\(k\)\(cnt\)的大小关系即可

!!!

需要特判一下,如果一开始集合中就只有一个数,那么无论操作多少次最后都只会有一个数,如果一开始的这个数不是1,最后的\(gcd\)一定会\(>1\),直接输出就好了

Code

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

int l,r,k,T;
int main() {
	cin>>T;
	while(T--) {
		cin>>l>>r>>k;
		int cnt=(r-l+1)/2;
		if(l&1 && r&1) cnt++;
		if(k>=cnt) {
			puts("Yes");
			continue;
		}
		if(l==r && l>1) {
			puts("Yes");
			continue;
		}
		puts("No");
	}
}

C

题意: 有一个原始序列,长度为\(n\),序列中的每个数\(a[i]\)都满足\(0<=a[i]<=n\),我们可以对序列进行操作,每次取一个长度\(k\),求出序列\(a[]\)的前\(k\)个数的\(MEX(a(k))\),加入新序列\(b[]\)的尾部.
其中\(MEX(X)\)的定义是没有在集合X的中出现的最小自然数,如X={0,1,3,2,3,5,3,7},那么\(MEX(X)=4\),因为0,1,2,3都在X中出现过
求字典序最大的\(b\)

Sol: 很明显,要求字典序最大,那么\(b\)序列中前面的数越大越好,当\(p=n\)时结果必然最大,设\(p\)\(a[]\)\(MEX(a(k))\)的位置,我们当然希望\(p\)越小越好,方便我们第二次寻找.
如上面的例子中,\(a(5)\)表示取\(a[]\)的前五个数,\(0,1,3,2,3,MEX(a(5))=4\),所以\(p=5\)
我们每次求出最大的\(MEX(a)\),找到同样能满足这个条件的\(MEX(a(p))\),然后删掉前p个数,对新的\(a\)继续求MEX
模拟一下最后一个样例

10
0 0 2 1 1 1 0 0 1 1
第一次 MEX=3 k=4 
此时a为 
1 1 0 0 1 1
第二次 MEX=2 k=3
此时a为
0 1 1
第三次 MEX=2 k=2
此时a为
1
第四次 MEX=0 k=1
此时a为空

最后的结果即为
b={3,2,2,0}
长度为4

大致思路应该没问题,可能会有一些实现方面的难度,如删除前k个数
我们用队列当一个桶,对于每个\(a[i]\),存下它每次出现的位置

for (int i=1;i<=n;i++) {
	cin>>a[i];
	q[a[i]].push(i);
}

后面每次找时,就从0开始找,找到一个数如果没有在这个序列中出现过就是答案
我们更新好上面提到的\(p\)也就是代码中的r后,我们需要把原序列中\(<=r\)的数的位置清空,防止影响后面的\(r\)的更新

另外为什么要加这句话呢

if(ans[ans.size()-1]==0) {
	r++;
	continue;
}

这是因为当最后只剩下一堆非0的数时,求出的MEX=0,我们的\(r\)不会更新,那么r将永远\(<n\)陷入死循环,手动+1跳出这个循环

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;

int T,n;
queue<int>q[N];
int a[N];

int main() {
	cin>>T;
	while(T--) {
		cin>>n; vector<int>ans;
		for (int i=1;i<=n;i++) {
			cin>>a[i];
			q[a[i]].push(i);
		}
		int r=0;
		while(r<n) {
			for (int i=0;i<=n+1;i++) {
				if(q[i].empty()) {
					ans.push_back(i);
					break;
				}
				r=max(r,q[i].front()); 
			}
			if(ans[ans.size()-1]==0) {
				r++;
				continue;
			}
			for (int i=0;i<ans[ans.size()-1];i++) {
				while(!q[i].empty() && q[i].front()<=r) q[i].pop();
			}
		}
		cout<<ans.size()<<endl;
		for (int i=0;i<ans.size();i++) cout<<ans[i]<<" ";cout<<endl;
		for (int i=0;i<=n;i++) {
			while(!q[i].empty()) q[i].pop();
		}
	}
}

D

题意: 多组数据,每组数据给定n个长度不超过3的字符串,问是否能通过删除若干个字符串使得剩余的字符串能组成一个回文串

Sol:
特判两种情况

1. 若这n个字符串中已经有回文串了,那么删除剩余n-1个回文串必然满足条件
2. 某个字符串的长度为1,同样删除剩下n-1个字符串必然满足条件

剩下的情况中,我们可以分为长度为2的字符串\(ab\)与长度为2的字符串\(ba\)组合形成类似\(abba\)的回文串,下面简称\(2+2\),同样我们还有

2+3 如ab+xba=>abxba 其中ab为给定的字符串
3+2 如abc+ba=>abcba 其中abc为给定的字符串
3+3 如abc+cba=>abccba 其中abc为给定的字符串

上面的\(x\)可以任取,我们\(for\)循环枚举每个字母实现,最后拿map一个一个判断就好了

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;

int T,n;
string s[N];

string work() {
	cin>>n; map<string,bool>mp;
	for (int i=1; i<=n; i++) cin>>s[i];
	for (int i=1; i<=n; i++)
		if(s[i][0]==s[i][s[i].length()-1]) return "Yes";
	for (int i=1;i<=n;i++) {
		if(s[i].length()==2) {
			string tmp="";
			tmp+=s[i][1];
			tmp+=s[i][0];
			if(mp[tmp]) return "Yes";
			//2+2
			for (char k='a';k<='z';k++) if(mp[tmp+k]) return "Yes";
			//2+3
		}
		else {
			string tmp="";
			tmp+=s[i][2];
			tmp+=s[i][1];
			if(mp[tmp] || mp[tmp+s[i][0]]) return "Yes";
			//3+2和3+3
		}
		mp[s[i]]=1;
	}return "No";
}

int main() {
	cin>>T;
	while(T--) cout<<work()<<endl; 
	return 0;
}
posted @ 2022-01-23 18:45  real_l  阅读(39)  评论(0编辑  收藏  举报