Codeforces Global Round 5 A B C1 C2 D

Codeforces Global Round 5

A: 偶数直接除2, 余下偶数个奇数,一半向上取整,一半向下取整

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

int n;
int a[N];
int vis[N];
int main(){
	scanf("%d", &n);
	int cnt = 0;
	for(int i = 0; i < n; i++){
		scanf("%d", &a[i]);
		if(a[i]%2 == 0){
			cnt++;
		}
	}
	int yu = (n - cnt)/2;
	int j = 0;
	for(int i = 0; i < n; i++){
		if(a[i]%2 ==0){
			a[i] /= 2;
		}
		else if(j < yu ){
			a[i] = (a[i]+1)/2;
			j++;
		}
		else a[i] = (a[i]-1)/2;
	}
	for(int i = 0; i < n; i++){
		printf("%d\n", a[i]);
	}
	return 0;
}

B:vis[i] 标记 i 是否超车, 遍历未超车的a[j], 找到第一个与 a[j] 相等的 b[i] , i 之前的标记为超车

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

int n;
int a[N];
int b[N];
int vis[N];
int main(){
	scanf("%d", &n);
	for(int i = 0;i < n; i++){
		scanf("%d", &a[i]);
	}
	for(int i = 0;i < n; i++){
		scanf("%d", &b[i]);
	}
	int cnt = 0;
	int j = 0;
	for(int i = 0; i < n && j < n; i++){
		if(vis[a[j]]) {
			j++;
			i--;
			continue;
		}
		if(b[i] == a[j]){
			j++;
			cnt++;
		}
		else{
			vis[b[i]] = 1;
		}
	}
	printf("%d\n", n-cnt);
	return 0;
}

C1:按x,y,z排序, 将所有点排序,首先将x 、y相同, z不同的按顺序两两配对,再将x 相同的为配对点, 按顺序两两配对,

最后将剩下的两两配对。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e3+10;
 
int n;
struct point{
	int x, y, z;
	int num;
	bool operator < (const point &p) const{
		if(x != p.x) return x < p.x;
		else if(y != p.y) return y < p.y;
		else return z < p.z;
	}
}p[N];
int vis[N];
vector< pair<int, int> > ans;
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
		p[i].num = i;
	}
	sort(p+1, p+1+n);
	for(int i = 1;i <= n; i++){
		if(vis[p[i].num]) continue;
		for(int j = i+1;j <= n; j++){
			if(i == j || vis[p[j].num]) continue;
			if(p[i].x == p[j].x && p[i].y == p[j].y){
				ans.push_back(make_pair(p[i].num, p[j].num));
				vis[p[i].num] = vis[p[j].num] = 1;
				break;
			}
		}
	}
	for(int i = 1;i <= n; i++){
		if(vis[p[i].num]) continue;
		for(int j = i+1;j <= n; j++){
			if(i == j || vis[p[j].num]) continue;
			if(p[i].x == p[j].x && p[i].y != p[j].y){
				ans.push_back(make_pair(p[i].num, p[j].num));
				vis[p[i].num] = vis[p[j].num] = 1;
				break;
			}
		}
	}
	int u, v;
	for(int i = n; i >= 1; ){
		int x[2];
		int flag = 1;
		for(int j = 0; j < 2; j++){
			while(vis[p[i].num] && i >= 1){
				i--;
			}
			if(i < 1) {
				flag = 0;
				break;
			}
			x[j] = p[i].num;
			i--;
		}
		if(flag == 0) break;
		ans.push_back(make_pair(x[0], x[1]));
	}
	for(auto u:ans){
		printf("%d %d\n", u.first, u.second);
	}
	return 0;
}

C2:思路和C1一样,用个vector、map维护一下就好

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5+10;
 
int n;
struct point{
	int x, y, z;
	int num;
	bool operator < (const point &p) const{
		if(x != p.x) return x < p.x;
		else if(y != p.y) return y < p.y;
		else return z < p.z;
	}
}p[N];
int vis[N];
vector< pair<int, int> > ans;
vector<int> po[N];
map< pair<int, int> , int > mp;
map<int, int> mp2;
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
		p[i].num = i;
	}
	sort(p+1, p+1+n);
	int pos, cnt = 0;
	for(int i = 1;i <= n; i++){
		pair<int, int> pa = make_pair(p[i].x, p[i].y);
		if(mp.count(pa)){
			pos = mp[pa];
		}
		else{
			pos = ++cnt;
			mp[pa] = pos;
		}
		po[pos].push_back(p[i].num);
	}
	
	for(int i = 1;i <= cnt; i++){
		if(po[i].size() >= 2) 
			for(int j = 0; j < po[i].size()-1; j += 2){
				ans.push_back(make_pair(po[i][j], po[i][j+1]));
				vis[po[i][j]] = vis[po[i][j+1]] = 1;
			}
		po[i].clear();
	}
	pos, cnt = 0;
	for(int i = 1;i <= n; i++){
		if(vis[p[i].num]) continue;
		if(mp2.count(p[i].x)){
			pos = mp2[p[i].x];
		}
		else {
			pos = ++cnt;
			mp2[p[i].x] = pos;
		}
		po[pos].push_back(p[i].num);
	}
	for(int i = 1;i <= cnt; i++){
		if(po[i].size() >= 2) 
			for(int j = 0; j < po[i].size()-1; j += 2){
				ans.push_back(make_pair(po[i][j], po[i][j+1]));
				vis[po[i][j]] = vis[po[i][j+1]] = 1;
			}
		po[i].clear();
	}
	int u, v;
	for(int i = n; i >= 1; ){
		int x[2];
		int flag = 1;
		for(int j = 0; j < 2; j++){
			while(vis[p[i].num] && i >= 1){
				i--;
			}
			if(i < 1) {
				flag = 0;
				break;
			}
			x[j] = p[i].num;
			i--;
		}
		if(flag == 0) break;
		ans.push_back(make_pair(x[0], x[1]));
	}
	for(auto u:ans){
		printf("%d %d\n", u.first, u.second);
	}
	return 0;
}

D: 当max(a) <=  2*min(a) 时答案全为-1, 否则答案最大为2*n,

二分枚举每个起点的答案,

用线段树维护区间最大值、最小值和区间是否合法(区间 [l,r] ,任意点 i ,都有 max_{l\rightarrow i} <= 2*a[i] )

要是区间 [l,r]​​​​​​​ 合法,则该区间左儿子Lson、右儿子Rson合法,并且max(Lson)<= 2*min(Rson)

查询:每次先向左查询,last_max表示已查询区间前面的最大值, 对于正在查询的区间如果区间合法并且当前区间最小值min*2 >= last_max , 那么该区间合法, return 1;

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
int n;
int a[N];
struct node{
	int mi, ma;
	int flag;
}tr[N*4];
int last_max;
void up(int o, int l, int r, int pos, int v){
	if(l == r){
		tr[o].ma = tr[o].mi = v;
		tr[o].flag = 1;
		return ;
	}
	int mid = l+r>>1;
	if(pos <= mid) up(o<<1, l, mid, pos, v);
	else up(o<<1|1, mid+1, r, pos, v);
	tr[o].ma = max(tr[o<<1].ma, tr[o<<1|1].ma);
	tr[o].mi = min(tr[o<<1].mi, tr[o<<1|1].mi);
	if(tr[o<<1].flag == 0 || tr[o<<1|1].flag == 0 || tr[o<<1].ma > tr[o<<1|1].mi*2){
		tr[o].flag = 0;
	}
	else tr[o].flag = 1;
}

int qu(int o, int l, int r, int ql, int qr){
	if(ql <= l && qr >= r){
		int flag = 1;
		if(last_max > tr[o].mi*2 || tr[o].flag == 0)
			flag = 0;
		last_max = max(last_max, tr[o].ma);
		return flag;
	}
	int mid = l+r>>1;
	int ans = 1;
	if(ql <= mid) ans *= qu(o<<1, l, mid, ql, qr);
	if(qr > mid) ans *= qu(o<<1|1, mid+1, r, ql, qr);
	return ans;
}

int main(){
	cin >> n;
	int mi = 1e9+10, ma = 0;
	for(int i = 0; i < n; i++){
		cin >> a[i];
		mi = min(mi, a[i]);
		ma = max(ma, a[i]);
	}
	if(mi*2 >= ma){
		for(int i = 0; i < n; i++){
			printf("-1%c", i == n-1?'\n':' ');
		}
		return 0;
	}
	for(int i = 0; i < 3*n; i++){
		up(1, 1, 3*n, i+1, a[i%n]);
	}
	for(int i = 1; i <= n; i++){
		int l = 1, r = 2*n-1, mid;
		while(l <= r){
			mid = l+r>>1;
			last_max = 0;
			if(qu(1, 1, 3*n, i, i+mid)) l = mid + 1;
			else r = mid - 1;
		}
		cout << r+1 << " ";
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值