Codeforces Round #767 (Div. 2)题解

A Download More RAM

题解

有n个软件,最初有k个内存,每个软件运行需要ai的内存,运行完可以获得bi个内存,问最后可以获得多少内存?
通过排序先运行所需内存小的软件以获得内存,即排序。

代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 111;
struct ab
{
	int a, b;
} arr[maxn];
bool cmp(ab a, ab b){
	return a.a < b.a;
}
int main(){
	int t; cin >> t;
	while(t--){
		int n, k; cin >> n >> k;
		for(int i = 0; i < n; i++) {
			cin >> arr[i].a;
		}
		for(int i = 0; i < n; i++){
			cin >> arr[i].b;
		}
		ll ans = k;
		sort(arr, arr + n, cmp);
		int pos = 0;
		while(arr[pos].a <= ans && pos < n){
			ans += arr[pos].b;
			pos++;
		}
		cout << ans << '\n';
	}
}

B GCD Arrays

题目

给你 l l l r r r这一段序列,在经过k次操作后,该段序列的最大公因数(即当前序列中的所有数字求解gcd)能否是大于1的数
操作:
从序列中取两个数字,将他们永久的从序列中删除,并加两者的乘积加入到队列中

题解

计算连续数字奇数的个数,即为可操作的最大个数,举例如下
初始状态 3 , 4 , 5 , 6 , 7 3,4,5,6,7 34567
第一次操作 3 ∗ 5 , 4 , 6 , 7 3*5,4,6,7 35467
第二次操作 3 ∗ 5 ∗ 7 , 4 , 6 3*5*7,4,6 35746
可以发现如上两次操作所得序列的gcd都是1
第三次操作 3 ∗ 5 ∗ 7 ∗ 4 , 6 3*5*7*4,6 35746
第四次操作 3 ∗ 5 ∗ 7 ∗ 4 ∗ 6 3*5*7*4*6 35746
显然从第三次操作起开始序列存在大于1的公因数了
那么解题思路就是所有奇数结合再加一个偶数序列即可得到大于1的公因数了

计算奇偶数的办法

		ll odd  = (r - l + 1) / 2;
		ll even = (r - l + 1) / 2;
		if ((r - l + 1) % 2 == 1 && r % 2 == 1) odd ++;
		else even ++;

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
	//freopen("in.txt","r",stdin);
	int t; cin >> t;
	while(t--){
		ll l, r, k;
		cin >> l >> r >> k;

		if (l == r)
		{
			if (l == 1)
				printf("NO\n");
			else
				printf("YES\n");

			continue;
		}
		ll odd  = (r - l + 1) / 2;
		ll even = (r - l + 1) / 2;
		if ((r - l + 1) % 2 == 1 && r % 2 == 1) odd ++;
		else even ++;
		//3个奇数可以操作三次
		
		//printf("%lld\n", odd);
		if (odd <= k){
			printf("YES\n");
		}
		else{
			printf("NO\n");
		}
	}
}

C Meximum Array

Mex (mathematics)

补集的最小值

题意

给你n个非负数字,你可以进行如下操作,每次选择连续的k个数字,求解这k个数字的Mex,然后放到b序列中,问最长长度为m的字典序的b序列里面的元素是什么?求解数字m和m个元素。

题解

题目要求是要字典序最大的,那么第一个位置一定是整个序列最大MEX,即满足
M E X ( p , j ) = M E X ( p , n ) MEX(p,j)=MEX(p, n) MEX(p,j)=MEX(p,n)
找到满足这个条件的第一个数字,然后消除前k个数,然后继续递归。

参考
假如是这一个序列 2 2 3 4 0 1 2 0 可以发现选择1 ~ 8和选择1 ~6所得到的结果是一样的,
那么我们就可以直接选择删除的是1 ~ 6

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int main(){
    //freopen("in.txt","r",stdin);
    int _;
    for(scanf("%d", &_); _; _--){
        ll n; cin >> n;
        std::vector<ll> arr(n + 1); // 输入n个元素
        std::vector<vector<ll> > idx(n + 1); //记录数字x出现的位置分别为多少
        for(int i = 0; i < n; i++) { 
            cin >> arr[i];
            idx[arr[i]].push_back(i); //arr[i]出现的位置为i
        }

        std::vector<ll> res; //存储答案
        ll init = 0;
        ll mex = 0;
        ll cur = -1;

        while(init < n){
            mex = 0;
            cur = init;
            //0<=ai<=n
            for(int i = 0; i <= n; i++){
                auto it = lower_bound(idx[i].begin(), idx[i].end(), init); 
                //查找init位置上是否有i
                if (it == idx[i].end()){
                    //如果没找到,mex就是i
                    mex = i;
                    break;
                }
                else {
                    cur = max(*it, cur);
                }
            }
            init = cur + 1; //找下一个位置
            res.push_back(mex);
        }
        cout << res.size() << '\n';
        for(int i = 0; i < res.size(); i++) cout << res[i] << " ";
            cout <<  '\n';

    }
}

D. Peculiar Movie Preferences

题意

给你n个字符串,每个字符串长度不超过3,问是否能组成回文串

题解

由于字符串长度不超过3,那么可以分类讨论出以下几种情况

  1. 本身就为回文字符串,例如a,aa,aaa,aba
  2. 两个子集构成回文串,例如ab和ba,aab和baa
  3. 两个子集构成回文串,例如ab和cba,或者是abc和ba

注意

2
ab
bad
NO

所以badab是不符合的,即相对顺序不变

代码

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

#define rep(i, a, b) for (int i=a;i<=b;++i)
const int mod = int(1e9) + 7;
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3fLL;
const double pi = acos(-1.0); //M_PI;
const int maxn = 1e5 + 10;

//给你n个字符串,每个字符串长度不超过3,问是否能组成回文串


int main(){
	//freopen("in.txt","r",stdin);
	//freopen("aout.txt","w",stdout);
	int _;
	for(scanf("%d", &_); _; _--){
		int n; cin >> n;
		bool flag = false;

		std::vector<string> arr(n);
		multiset<string> suf, pre;//pre记录前面出现的,suf记录后面出现的,TLE5

		for(int i = 0; i < n; i++){
			cin >> arr[i];
			suf.insert(arr[i]);
		}

		for(int i = 0; i < n; i++){
			suf.erase(suf.find(arr[i]));

			string now = arr[i];

			reverse(now.begin(), now.end());
			//aba ab ba
			if (suf.count(now)){
				flag = true;
				break;
			}

			if (arr[i].size() == 1){
				flag = true;
				break;
			}

			if (arr[i].size() == 2){
				if (arr[i][0] == arr[i][1]){
					flag = true;
					break;
				}
			}
			if (arr[i].size() == 3){
				if (arr[i][0] == arr[i][2]){
					flag = true;
					break;
				}
			}

			if (arr[i].size() == 3){
				//cb abc 
				string t1 = arr[i].substr(1, 2);
				reverse(t1.begin(), t1.end());

				if (pre.count(t1)){
					flag = true;
					break;
				}
				//abc ba
				string t2 = arr[i].substr(0, 2);
				reverse(t2.begin(), t2.end());
				if (suf.count(t2)){
					flag = true;
					break;
				}

			}
			pre.insert(arr[i]);
		}
		if (flag){
			printf("YES\n");
			continue;
		}
		else {
			printf("NO\n");
			continue;
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值