Codeforces Round #649 (Div. 2) A~C题解

目录

A. XXXXX

B. Most socially-distanced subsequence

C. Ehab and Prefix MEXs


A. XXXXX

题意:给长度为n的数组A,问能否选出一个子数组使得子数组的和模X不为0,要求子数组的和尽量大。

思路:如果A[i] % x \small \equiv 0,则无子数组满足要求,若数组和模X不为0,则答案为n,否则只要找到第一个模X不为0的A[i]和最后一个两者对比长度就可以。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-06-14 01:31
 *Link: https://codeforces.com/contest/1364/problem/A
 *-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n, x;
		scanf("%d %d", &n, &x);
		vector<int> a(n);
		int sum = 0;
		bool flag = 0;
		for(int i = 0; i < n; ++i) scanf("%d", &a[i]), sum += a[i], flag |= (a[i] % x != 0);
		if(sum % x != 0) printf("%d\n", n);
		else if(!flag) printf("-1\n");
		else{
			int pre, suf;
			pre = n - 1, suf = 0;
			for(int i = 0; i < n; ++i){
				if(a[i] % x != 0){
					pre = i;
					break;
				}
			}
			for(int i = n - 1; i >= 0; --i){
				if(a[i] % x != 0){
					suf = i;
					break;
				}
			}
			int ans = max(n - 1 - pre, suf);
			printf("%d\n", ans);
		}

	}
	return 0;
}

B. Most socially-distanced subsequence

题意:给长度为N的数组A,问能否选出一个长度为K的子序列S,子序列S\small \left | s_{1}- s_{2} \right | + \left | s_{2} - s_{3} \right | + ...... + \left | s_{k - 1} - s_{k}\right |最大。输出选择的数。

思路:如果把数组A在二维图坐标系上标出,横坐标为位置,纵坐标为A[i],然后按顺序连接所有点,最后呈现一个折线图,很容易就发现,选择的点必定都是转折点X,X和X-1连成线段所在直线的斜率与X+1和X连成线段所在直线的斜率一个为正一个为负。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-06-13 22:51
 *Link: 
 *-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n;
		scanf("%d", &n);
		vector<int> a(n);
		vector<int> ans;
		for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
		bool flag = a[1] > a[0];
		ans.pb(a[0]);
		for(int i = 1; i < n; ++i){
			if(i == n - 1){
				ans.pb(a[i]);
				break;
			}
			bool tmp = a[i + 1] > a[i];
			if(tmp == flag) continue;
			else {
				flag ^= 1;
				ans.pb(a[i]);
			}
		}
		printf("%d\n", ans.size());
		for(int i = 0; i < ans.size(); ++i) printf("%d%c", ans[i], i == ans.size() - 1? '\n' : ' ');
	}
	return 0;
}

C. Ehab and Prefix MEXs

题意:给出长度为N的数组A,要求构造出一个数组B,对于任意一个B[i],要求MEX{B[1], B[2], B[3], ...... , B[i]} = A[i]。MEX(...)定义为:子数组B[1] ~ B[i]中没有出现的非负数中的最小值。

思路:由于输入条件(\small a_{i} \leq a_{i + 1} for1\leq i< n)的限制,导致这题必定是没有构造不出的情况,因为只有A数组为:1 2 3 4 2,类似这样的情况出现时才无法构造。即A[i] < A[j], i > j 的情况出现才会无法构造。且同时因为输入条件(\small a_{1}, a_{2},......, a_{n}(0\leq a_{i} \leq i))的限制,所以用于构造的数必定小于n,用两个set:S和U分别存还没有使用过的数和没有出现过且没有用于构造B数组的数。当\small *S.begin() > A[i] - 1时,则代表在1~ i - 1之中,0~\small A[i] - 1已经全部出现,因此可以腾出一个位置去填其他数,那么肯定是填U中的数更佳,因为这样有利于后面数组的填充,这就是为什么样例3中B[2] = 2的原因。如果\small *S.begin() < A[i] - 1,那肯定时填*S.begin()。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-06-13 22:51
 *Link: 
 *-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;

int a[maxn];
int b[maxn];
bool vis[maxn];

int main(){
	int n;
	scanf("%d", &n);
	int Max = -1;
	int x;
	map<int, int> mp;
	for(int i = 1; i <= n; ++i){
		scanf("%d", &a[i]);
		mp[a[i]] = i;
	}
	set<int> s, u;
	for(int i = 0; i <= n; ++i) {
		s.insert(i);
		if(mp[i] == 0) u.insert(i);
	}
	for(int i = 1; i <= n; ++i){
		int x = a[i] - 1;
		if(*s.begin() > x){
			b[i] = *u.begin();
			u.erase(u.begin());
			if(s.find(b[i]) != s.end())s.erase(b[i]);
		}
		else{
			b[i] = *s.begin();
			if(s.find(b[i]) != s.end())s.erase(b[i]);
			if(u.find(b[i]) != u.end())u.erase(b[i]);
		}
	}
	for(int i = 1; i <= n; ++i) printf("%d ", b[i]); printf("\n");
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值