Codeforces Global Round 5 补题(C2思维、D二分+ST/二分+单调栈、E思维)

思路来源

tourist的turorial

C2. Balanced Removals (Harder)(map)

给n(n<=5e4,n为偶数)个点,每次删掉两个点,删的时候

以两个点构成的正方体[min(x1,x2),max(x1,x2)][min(y1,y2),max(y1,y2)][min(z1,z2),max(z1,z2)]内,

不能有其他点(含边界),题目保证点两两不同,要求输出一组删点顺序

考虑先删x和y相同时z不同的,这样最后x和y相同时z不同的最多只剩一个

删完再删x相同时y不同的,同理,最多剩一个

再删x不同的

tourist神仙代码

iota(t.begin(),t.end(),0);//从0起 连续赋值0 1 2... 头文件numeric

#include<iostream>
#include<cstdio>
#include<numeric>
#include<vector>
#include<map>
using namespace std;
const int D=3; 
int n;
int dfs(vector<vector<int> >&p,vector<int> &x,int k)
{
	if(k==D){//由于所有值不同 最后一层 一定只有一个值 
		return x[0];
	}
	map<int,vector<int> >mp;
	for(int &v:x){
		mp[p[v][k]].push_back(v);
	}
	vector<int>a;
	for(auto &q:mp){
		int cur=dfs(p,q.second,k+1);
		if(cur!=-1){
			a.push_back(cur);
		}
	}
	int len=a.size();
	for(int i=0;i+1<len;i+=2){
		printf("%d %d\n",1+a[i],1+a[i+1]);
	}
	return len%2?a.back():-1;
}
int main()
{
	scanf("%d",&n);
	vector<vector<int> >p(n,vector<int>(D));
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<D;++j)
		scanf("%d",&p[i][j]);
	}
	vector<int> t(n);
	iota(t.begin(),t.end(),0);//从0起 连续赋值 
	dfs(p,t,0);
	return 0;
}

D. Balanced Playlist(ST+二分/单调栈+二分)

快到1点的时候想出了思路然后没写完,我tm是来搞笑的吧,不说了都是泪

ST部分可以用单调栈搞搞

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int dp[N][20];
int n,a[N],ans[N],mn,mx,now,pos;
void ST(int tot)
{
	for(int i=1;i<=tot;++i)
	dp[i][0]=i;//�������Сֵ���±� 
	for(int len=1;(1<<len)<=tot;++len)
	{
		for(int l=1;l+(1<<len)-1<=tot;++l)
		{
			if(a[dp[l][len-1]]<=a[dp[l+(1<<(len-1))][len-1]])dp[l][len]=dp[l][len-1];
			else dp[l][len]=dp[l+(1<<(len-1))][len-1];
		}
	}
}
int RMQ(int l,int r)//������Сֵ�±� 
{
	int len=log(r-l+1)/log(2);
	if(a[dp[l][len]]<=a[dp[r-(1<<len)+1][len]])return dp[l][len];
	return dp[r-(1<<len)+1][len];
}
void solve()
{
	if(mx<=mn*2)
	{
		for(int i=1;i<=n;++i)
		printf("%d%c",-1," \n"[i==n]);
		return;
	}
	for(int i=1;i<=n;++i)
	{
		int &v=a[i];
		a[i+2*n]=v;
		a[i+n]=v;
	}
	ST(3*n);
	pos=3*n,now=a[n];
	for(int i=n+1;i<=3*n;++i)
	{
		if(a[i]*2<now)
		{
			pos=i;
			break;
		}
		now=max(now,a[i]);
	}
	ans[n]=pos;
	for(int i=n-1;i>=1;--i)
	{
		if(a[i]>a[i+1])
		{
			int l=i,r=pos-1;
			while(l<=r)
			{
				int mid=(l+r)/2;
				if(a[RMQ(i,mid)]*2<a[i])r=mid-1;//i<=pos-1
				else l=mid+1;
			}
			if(a[l]*2<a[i])pos=min(pos,l);
		}
		ans[i]=pos;
	}
	for(int i=1;i<=n;++i)
	{
		ans[i]-=i;//[i,ans[i])
		printf("%d%c",ans[i]," \n"[i==n]);
	}
}
int main()
{
	scanf("%d",&n);
	mn=1e9+1;mx=0;
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		mn=min(mn,a[i]);
		mx=max(mx,a[i]);
	}
	solve();
	return 0; 
}

E. Balanced Binary Search Trees(思维题)

一棵n(n<=1e6)个节点的二叉搜索树,求满足以下三个条件的树形数

①树是等节点合法二叉搜索树中最矮的

②对于每个节点i,左子树lson填的数和i奇偶性不同,右子树rson填的数和i奇偶性相同

③树的每个点的键值由1到n共n个数,不重复

注意到n这个key一定在右子树里,与其父,父的父,…,rt奇偶性相同,

rt与n奇偶性相同,即rt的右子树个数必为偶数,

归纳法构造这棵树,

深度为0时,1合法;深度为1时,2合法

深度为2时,4和5合法;深度x只能由两个深度x-1的子树构造(不然层数不等)

深度3时,9和10合法

由于递归构造,显然树形固定,值也就只有一种填法了

因此,如果n出现在该序列中,则答案为1,否则为0

#include<iostream>
#include<cstdio>
#include<numeric>
#include<vector>
#include<map>
using namespace std;
int n; 
int solve(int n)
{
	int x=1;
	while(x<=n)
	{
		if(n==x||n==x+1)return 1;
		if(x%2==0)x=x+1+x;
		else x=x+1+(x+1);
	}
	return 0;
}
int main()
{
	scanf("%d",&n);
	printf("%d\n",solve(n));
	return 0;
}
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/102611508