思路来源
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;
}