Codeforces Round #759 (Div. 2, based on Technocup 2022 Elimination Round 3)ABCDE

A. Life of a Flower

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=110;
int w[N];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for( int i=1;i<=n;i++){
			cin>>w[i];
		}
		int flag=1;
		for( int i=2;i<=n;i++){
			if(w[i]==0&&w[i-1]==0){
				flag=0;
			}
		}
		if(flag==0){
			cout<<-1<<endl;
			continue;
		}
		int ans=1;
		for( int i=1;i<=n;i++){
			if(w[i]==1&&w[i-1]==0) ans++;
			if(w[i]==1&&w[i-1]==1) ans+=5;
		}
		cout<<ans<<endl;
	}
	return 0;
}

B. Array Eversion

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=200100;
int w[N];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		int maxn=0;
		for( int i=1;i<=n;i++){
			cin>>w[i];
			maxn=max(maxn,w[i]);
		}
		int ans=0;
		int x=0;
		for( int i=n;i>=1;i--){
			if(maxn==w[i]) break;
			if(w[i]>x) {
				ans++;
				x=w[i];
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

C. Minimize Distance

贪心算法
将正数和负数分别存储,然后排序

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=200100;
vector<int>pos,neg;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,k;
		cin>>n>>k;
		pos.clear();
		neg.clear();
		int maxn=0;
		long long ans=0;
		for( int i=1;i<=n;i++){
			int x;
			cin>>x;
			if(x>=0) pos.push_back(x);
			else neg.push_back(-x);
			maxn=max(maxn,abs(x));
		}
		sort(pos.begin(),pos.end());
		sort(neg.begin(),neg.end());
		if(!pos.empty()){
			for (int i=(pos.size())-1;i>=0;i-=k) {
				ans+=2*pos[i];
			}
		}
		if(!neg.empty()){
			for( int i=(neg.size())-1;i>=0;i-=k){
				ans+=2*neg[i];
			}
		}
		cout<<ans-(long long)maxn<<endl;
	}
	return 0;
}

D. Yet Another Sorting Problem

考察的是排列的奇偶性。
对于某个排列,某个元素的值为i,将i和第i个位置的数连上一条边。
那么排列的奇偶性就是n-环数

排列的奇偶性也可以通过求解逆序对的对数来求解。

对于某个排列,如果交换两个元素,会改变排列的奇偶性。

本题中,交换三个元素,排列的奇偶性不变,由于最后的奇偶性是偶数,所以如果最后的奇偶性是偶数,那么就可以排序,反之不能排序。
如果有多个相同元素,那么交换后奇偶性改变,但是数组不变,因此一定有解。

判断图中有几个环,用并查集即可,因为环是强连通的,

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=500100;
int w[N];
int fa[N];
int find(int x){
	if(x!=fa[x]) fa[x]=find(fa[x]);
	return fa[x];
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		set<int>se;
		for( int i=1;i<=n;i++){
			cin>>w[i];
			se.insert(w[i]);
			fa[i]=i;
		}
		if(n==1||se.size()<n){
			cout<<"YES"<<endl;
			continue;
		}
		if(n==2){
			if(w[1]<=w[2]) cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
			continue;
		}
		int cyc=n;
		for( int i=1;i<=n;i++){
			if(find(i)==find(w[i])) cyc--;//有环
			else {
				fa[find(i)]=find(w[i]);
			}
		}
		if(cyc%2==0){
			cout<<"YES"<<endl;
		}
		else {
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

E. Frequency Queries

cf的数据结构太肝了。。。。。
首先dfs求出每个结点的时间戳,然后把询问按时间戳排序,然后按时间戳的顺序求解答案。
对于每次寻问,我们需要维护一平衡树,平衡树按照每个数值出现的次数排序,
需要一个数组维护每个数值出现的次数,这样才能实现在树中查找pair的数据类型。
对于每次查找,首先找到小于x的数的个数,然后再找到答案的值。
最后将答案统一输出。

这里有几个技巧,再pbds平衡树中用pair当作元素需要修改比较函数,在比较时先比较第一个元素,在比较第二个元素

#include<bits/stdc++.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const int N=1000100;
const int inf=0x3f3f3f3f;

 
tree<pair<int,int> , null_type,less<pair<int,int> >,rb_tree_tag,tree_order_statistics_node_update>tr;
//平衡树,按照每个数的出现次数排序,第二关键字是a
int p[N],a[N];
//首先求解dfs序和时间戳

int cnt[N],step[N];//每个数的个数,时间戳
int cc,point;
int h[N],ne[N*2],to[N*2],idx;
int ans[N];
int n,q;

struct query{
	int v,l,k,id;
}qq[N];
void add( int a,int b){
	to[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void get_step(int rt,int fa){
	step[rt]=cc++;
	for( int i=h[rt];i!=-1;i=ne[i]){
		int j=to[i];
		if(j==fa) continue;
		get_step(j,rt);
	}
}
int cmp( query a,query b){
	return step[a.v]<step[b.v];
}

#define debug cout<<"debug::"<<rt<<step[qq[point].v]<<step[rt]<<endl;

void solve(int rt,int fa){
	int x=a[rt];
	if(cnt[x])
	tr.erase(make_pair(cnt[x],x));
	cnt[x]++;
	tr.insert(make_pair(cnt[x],x));
	while(step[qq[point].v]<step[rt]&&point<=q) point++;

	while(qq[point].v==rt&&point<=q){
		int cnt_pre=tr.order_of_key(make_pair(qq[point].l,-1));
		tree<pair<int,int> , null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>::iterator it;
		it=tr.find_by_order(cnt_pre+qq[point].k-1);

		if(it==tr.end()) ans[qq[point].id]=-1;
		else ans[qq[point].id]=it->second;
		point++;
	}
	for( int i=h[rt];i!=-1;i=ne[i]){
		int j=to[i];
		if(j==fa) continue;
		solve(j,rt);
	}
	tr.erase(make_pair(cnt[x],x));
	cnt[x]--;
	if(cnt[x])
		tr.insert(make_pair(cnt[x],x));
}
int main(){
	int t;
	cin>>t;
	while(t--){
		scanf("%d%d",&n,&q);
		cc=0,idx=0,point=1;
		for( int i=1;i<=n;i++){
			h[i]=-1;
			scanf("%d",&a[i]);
		}
		for( int i=2;i<=n;i++){
			int x;
			scanf("%d",&x);
			add(x,i);
			add(i,x);
		}
		get_step(1,0);
		step[n+1]=inf;
		for( int i=1;i<=q;i++){
			scanf("%d%d%d",&qq[i].v,&qq[i].l,&qq[i].k);
			qq[i].id=i;
		}
		sort(qq+1,qq+1+q,cmp);
		solve(1,0);
		for( int i=1;i<=q;i++){
			printf("%d ",ans[i] );
		}
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值