• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

7.21考试总结(NOIP模拟22)[d·e·f]

开发技术 开发技术 3小时前 1次浏览

你驻足于春色中,于那独一无二的春色之中。

前言

首先,这套题的暴力分数十分丰厚,大概是 81+89+30=200 。

T1 的特殊性质比较多,也都很好想,于是考场 81pts 是没有问题的。

T2 暴力求出所有点的公共的 LCA 然后,暴力上跳然后标记一下就好了。

但是,但是,我高级数据结构学傻了,先是建了一棵虚树,然后发现有些节点是不可以被删去的。。

然后我就开始把虚树上压缩了的路径在解压回来,暴力高(莫名多了一个建虚树的时间),喜挂 53pts

T3 树状数组求逆序对可以把暴力复杂度中的一个 n 降低为 logn 然后就有了 30pts。

但是,我竟然成了 CE 选手。。(第一次发现C++11不让用 rank 作为变量名)

T1 d

解题思路

对于所有的矩形,我们发现只有去掉当前长或者宽最小的才可以对答案有贡献。

因此可以枚举对于长或者宽最小的矩形去掉的数量,然后取出最优解。

但是这样的复杂度比正解多了一个 n 。

我们发现可以先把前 m 个宽最小的矩形先去掉,然后再一个一个恢复回来。

每恢复一个,就要再删除一个长最小矩形,用优先队列维护。

  • 注意:之前删除过的矩形不可以再删除一边,记录一下。。

c++ode

暴力+特殊性质81pts

#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e5+10,INF=1e9;
int T,n,m,ans;
bool flag,vis[N];
struct Node
{
	int x,y;
}s[N];
struct Node2
{
	int num,id;
}a[N],b[N];
bool comp1(Node x,Node y)
{
	return x.y<y.y;
}
void Sepcial_Judge1()
{
	sort(s+1,s+n+1,comp1);
	ans=s[m+1].x*s[m+1].y;
}
void Sepcial_Judge2()
{
	int minx=INF,miny=INF;
	for(int i=1;i<=n;i++)
	{
		minx=min(minx,s[i].x);
		miny=min(miny,s[i].y);
	}
	ans=minx*miny;
}
void Sepcial_Judge3()
{
	int maxn=0;
	for(int i=1;i<=n;i++)
		maxn=max(maxn,s[i].x*s[i].y);
	ans=maxn;
}
bool comp2(Node2 x,Node2 y)
{
	return x.num<y.num;
}
void solve()
{
	ans=0;
	for(int i=1;i<=n;i++)
	{
		a[i].num=s[i].x;
		b[i].num=s[i].y;
		a[i].id=b[i].id=i;
	}
	sort(a+1,a+n+1,comp2);
	sort(b+1,b+n+1,comp2);
	for(int res=0,pos,pos2;res<=m;res++)
	{
		pos=1;
		for(int i=1;i<=res;i++)
			vis[a[i].id]=true;
		pos2=res+1;
		for(int j=1;j<=m-res;j++)
		{
			while(vis[b[pos].id])
				pos++;
			vis[b[pos].id]=true;
		}
		while(vis[a[pos2].id])	pos2++;
		while(vis[b[pos].id])	pos++;
		ans=max(ans,a[pos2].num*b[pos].num);
		for(int i=1;i<=pos2;i++)
			vis[a[i].id]=false;
		for(int i=1;i<=pos;i++)
			vis[b[i].id]=false;
	}
}
signed main()
{
	T=read();
	while(T--)
	{
		n=read();
		m=read();
		flag=false;
		for(int i=1;i<=n;i++)
		{
			s[i].x=read();
			s[i].y=read();
			if(i!=1&&s[i-1].x!=s[i].x)
				flag=true;
		}
		if(!flag)	Sepcial_Judge1();
		else	if(!m)	Sepcial_Judge2();
		else	if(m==n-1)	Sepcial_Judge3();
		else	solve();
		printf("%lldn",ans);
	}
	return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e5+10,INF=1e9;
int T,n,m,ans;
bool flag,vis[N],v2[N];
struct Node
{
	int x,y;
}s[N];
struct Node2
{
	int num,id;
	bool friend	operator <(Node2 x,Node2 y)
	{
		return x.num>y.num;
	}
}a[N],b[N];
priority_queue<Node2> q;
bool comp2(Node2 x,Node2 y)
{
	return x.num<y.num;
}
void solve()
{
	while(!q.empty())	q.pop();
	memset(vis,false,sizeof(vis));
	memset(v2,false,sizeof(v2));
	for(int i=1;i<=n;i++)
	{
		a[i].num=s[i].x;
		b[i].num=s[i].y;
		a[i].id=b[i].id=i;
	}
	sort(a+1,a+n+1,comp2);
	for(int i=1;i<=m;i++)
		vis[a[i].id]=true;
	for(int i=1;i<=n;i++)
		if(!vis[b[i].id])
			q.push(b[i]);
	ans=a[m+1].num*q.top().num;
	for(int res=m;res;res--)
	{
		vis[a[res].id]=false;
		q.push(b[a[res].id]);
		v2[q.top().id]=true;
		q.pop();
		if(v2[a[res].id])
			continue;
		ans=max(ans,q.top().num*a[res].num);
	}
}
signed main()
{
	T=read();
	while(T--)
	{
		n=read();
		m=read();
		for(int i=1;i<=n;i++)
		{
			s[i].x=read();
			s[i].y=read();
		}
		solve();
		printf("%lldn",ans);
	}
	return 0;
}

T2 e

解题思路

直接在树上的节点上建主席树,历史版本为每个节点的父亲。

不难发现,(|a_i-r|) 最小的一定是 r 或者 r的前驱和后继。

于是我们只需要查找前驱后继就好了,无非就是在大于 r 的区间中找最小值,在小于 r 的区间中找最大值。

这是第一种打法,给出 pyt 的 (code)

我的打法当然不同于别人了。只要可以找到比 r 小的数的个数也就是 r 的排名不久好了??

接下来就是查询区间内排名第 k 大的数就好了(这不是板子??)。

查询的时候注意一下边界问题就好了。

当然这个题不用主席树其实也可以:

发现暴力跳LCA是被第 8 个点卡住,但是线段树套平衡树套线段树是卡在了第 7 个点。

因此 暴力加树套树可做!!!(JYFHYX的 (code)

c++ode

暴力跳 LCA

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e5+10,INF=1e9;
int n,m,lca,T,typ,opt,ans,las,s[N],q[N];
int tim,dfn[N],topp[N],siz[N],fa[N],son[N],dep[N];
bool vis[N];
struct Edge
{
	int tot,head[N],ver[N<<1],nxt[N<<1];
	void add(int x,int y)
	{
		ver[++tot]=y;
		nxt[tot]=head[x];
		head[x]=tot;
		ver[++tot]=x;
		nxt[tot]=head[y];
		head[y]=tot;
	}
}e1,e2;
inline void dfs1(int x)
{
	siz[x]=1;
	for(int i=e1.head[x];i;i=e1.nxt[i])
	{
		int to=e1.ver[i];
		if(siz[to])	continue;
		dep[to]=dep[x]+1;
		fa[to]=x;
		dfs1(to);
		siz[x]+=siz[to];
		if(siz[to]>siz[son[x]])
			son[x]=to;
	}
}
inline void dfs2(int x,int tp)
{
	dfn[x]=++tim;
	topp[x]=tp;
	if(son[x])
		dfs2(son[x],tp);
	for(int i=e1.head[x];i;i=e1.nxt[i])
	{
		int to=e1.ver[i];
		if(dfn[to])	continue;
		dfs2(to,to);
	}
}
inline int LCA(int x,int y)
{
	if(!x||!y)	return 0;
	while(topp[x]^topp[y])
	{
		if(dep[topp[x]]<dep[topp[y]])
			swap(x,y);
		x=fa[topp[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	return x;
}
inline void solve(int fro,int to)
{
	while(fro!=to)
	{
		if(vis[fro])	break;
		vis[fro]=true;
		ans=min(ans,abs(s[fro]-opt));
		fro=fa[fro];
	}
	vis[to]=true;
	ans=min(ans,abs(s[to]-opt));
}
signed main()
{
	n=read();
	T=read();
	typ=read();
	for(int i=1;i<=n;i++)
		s[i]=read();
	for(int i=1,x,y;i<n;i++)
	{
		x=read();
		y=read();
		e1.add(x,y);
	}
	dfs1(1);
	dfs2(1,1);
	while(T--)
	{
		memset(vis,false,sizeof(vis));
		vis[0]=true;
		ans=INF;
		opt=read();
		m=read();
		for(int i=1,x;i<=m;i++)
		{
			x=read();
			q[i]=(x-1+las*typ)%n+1;
		}
		if(m==1)
		{
			las=ans=abs(opt-s[q[1]]);
			printf("%lldn",ans);
			continue;
		}
		lca=q[1];
		for(int i=2;i<=m;i++)
			lca=LCA(lca,q[i]);
		for(int i=1;i<=m;i++)
			solve(q[i],lca);
		las=ans;
		printf("%lldn",ans);
	}
	return 0;
}

虚树 36pts

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e5+10,INF=1e9;
int n,m,root,rtdep,T,typ,opt,ans,las,s[N],q[N];
int top,sta[N];
int tim,dfn[N],topp[N],siz[N],fa[N],son[N],dep[N];
struct Edge
{
	int tot,head[N],ver[N<<1],nxt[N<<1];
	void add(int x,int y)
	{
		ver[++tot]=y;
		nxt[tot]=head[x];
		head[x]=tot;
//		/*
		ver[++tot]=x;
		nxt[tot]=head[y];
		head[y]=tot;
//		*/
	}
}e1,e2;
void dfs1(int x)
{
	siz[x]=1;
	for(int i=e1.head[x];i;i=e1.nxt[i])
	{
		int to=e1.ver[i];
		if(siz[to])	continue;
		dep[to]=dep[x]+1;
		fa[to]=x;
		dfs1(to);
		siz[x]+=siz[to];
		if(siz[to]>siz[son[x]])
			son[x]=to;
	}
}
void dfs2(int x,int tp)
{
	dfn[x]=++tim;
	topp[x]=tp;
	if(son[x])
		dfs2(son[x],tp);
	for(int i=e1.head[x];i;i=e1.nxt[i])
	{
		int to=e1.ver[i];
		if(dfn[to])	continue;
		dfs2(to,to);
	}
}
int LCA(int x,int y)
{
	if(!x||!y)	return 0;
	while(topp[x]^topp[y])
	{
		if(dep[topp[x]]<dep[topp[y]])
			swap(x,y);
		x=fa[topp[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	return x;
}
bool comp(int x,int y)
{
	return dfn[x]<dfn[y];
}
void build(int x)
{
	if(!top)
	{
		if(rtdep>dep[x])	root=x,rtdep=dep[x];
		sta[++top]=x;
		return ;
	}
	int lca=LCA(x,sta[top]);
	while(top>1&&dep[sta[top-1]]>dep[lca])
	{
//		cout<<sta[top-1]<<' '<<lca<<endl;
		e2.add(sta[top-1],sta[top]);
		top--;
	}
	if(dep[lca]<dep[sta[top]])
		e2.add(lca,sta[top--]);
	if(!top||sta[top]!=lca)
	{
		sta[++top]=lca;
		if(rtdep>dep[lca])	root=lca,rtdep=dep[lca];
	}
	sta[++top]=x;
	if(rtdep>dep[x])	root=x,rtdep=dep[x];
}
void solve(int fro,int to)
{
	while(fro!=to)
	{
//		f();
//		cout<<fro<<' '<<to<<endl;
//		cout<<fro<<endl;
		if(!fro)	break;
		ans=min(ans,abs(s[fro]-opt));
		fro=fa[fro];
	}
	ans=min(ans,abs(s[to]-opt));
}
void dfs3(int x,int fat)
{
//	cout<<x<<' '<<fat<<endl;
	if(!ans)	return ;
	for(int i=e2.head[x];i;i=e2.nxt[i])
	{
		int to=e2.ver[i];
		if(to==fat)	continue;
		solve(to,x);
		dfs3(to,x);
	}
}
signed main()
{
//	freopen("date.in","r",stdin);
	n=read();
	T=read();
	typ=read();
	for(int i=1;i<=n;i++)
		s[i]=read();
	for(int i=1,x,y;i<n;i++)
	{
		x=read();
		y=read();
		e1.add(x,y);
//		e1.add(y,x);
	}
	dfs1(1);
	dfs2(1,1);
//	f();
/*
	for(int i=1;i<=n;i++)
		cout<<dfn[i]<<' ';
*/
	while(T--)
	{
		e2.tot=top=0;
		ans=rtdep=INF;
		opt=read();
		m=read();
		memset(e2.head,0,sizeof(e2.head));
		for(int i=1,x;i<=m;i++)
		{
			x=read();
			q[i]=(x-1+las*typ)%n+1;
		}
		if(m==1)
		{
			las=ans=abs(opt-s[q[1]]);
			printf("%lldn",ans);
			continue;
		}
		sort(q+1,q+m+1,comp);
	//	f();
	//	cout<<root<<endl;
		for(int i=1;i<=m;i++)
			build(q[i]);
	//	f();
		while(--top)
		{
		//	cout<<sta[top]<<' '<<sta[top+1]<<endl;
			e2.add(sta[top],sta[top+1]);
		}
//		f();
//		cout<<root<<endl;
		dfs3(root,0);
//		f();
		las=ans;
		printf("%lldn",ans);
//		cout<<T<<endl;
	}
//	f();
	return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
#define ls tre[x].l
#define rs tre[x].r
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=5e5+10,INF=1e18;
int n,m,lca,T,typ,opt,ans,las,s[N];
int tim,dfn[N],topp[N],siz[N],fa[N],son[N],dep[N];
int all,root[N];
int cnt,lsh[N];
vector<int> v[N];
struct Edge
{
	int tot,head[N],ver[N<<1],nxt[N<<1];
	void add(int x,int y)
	{
		ver[++tot]=y;
		nxt[tot]=head[x];
		head[x]=tot;
		ver[++tot]=x;
		nxt[tot]=head[y];
		head[y]=tot;
	}
}e;
struct Segment_Tree
{
	int l,r,dat;
}tre[N*80];
struct Ques
{
	int dat,cnt;
}q[N];
inline void dfs1(int x)
{
	siz[x]=1;
	for(int i=e.head[x];i;i=e.nxt[i])
	{
		int to=e.ver[i];
		if(siz[to])	continue;
		dep[to]=dep[x]+1;
		fa[to]=x;
		dfs1(to);
		siz[x]+=siz[to];
		if(siz[to]>siz[son[x]])
			son[x]=to;
	}
}
inline void dfs2(int x,int tp)
{
	dfn[x]=++tim;
	topp[x]=tp;
	if(son[x])
		dfs2(son[x],tp);
	for(int i=e.head[x];i;i=e.nxt[i])
	{
		int to=e.ver[i];
		if(dfn[to])	continue;
		dfs2(to,to);
	}
}
inline int LCA(int x,int y)
{
	if(!x||!y)	return 0;
	while(topp[x]^topp[y])
	{
		if(dep[topp[x]]<dep[topp[y]])
			swap(x,y);
		x=fa[topp[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	return x;
}
int insert(int pre,int l,int r,int val)
{
	int x=++all,mid=(l+r)>>1;
	tre[x].dat=tre[pre].dat+1;
	if(l>=r)	return x;
	ls=tre[pre].l;
	rs=tre[pre].r;
	if(val<=mid)	ls=insert(tre[pre].l,l,mid,val);
	else	rs=insert(tre[pre].r,mid+1,r,val);
	return x;
}
int query_rank(int pre,int x,int l,int r,int val)
{
	if(l==r)	return tre[x].dat-tre[pre].dat;
	int mid=(l+r)>>1;
	int sum=tre[tre[x].l].dat-tre[tre[pre].l].dat;
	if(val<=mid)	return query_rank(tre[pre].l,tre[x].l,l,mid,val);
	return sum+query_rank(tre[pre].r,tre[x].r,mid+1,r,val);
}
int query(int pre,int x,int l,int r,int rk)
{
	if(l>=r)	return l;
	int mid=(l+r)>>1;
	int sum=tre[tre[x].l].dat-tre[tre[pre].l].dat;
	if(rk<=sum)	return query(tre[pre].l,tre[x].l,l,mid,rk);
	return query(tre[pre].r,tre[x].r,mid+1,r,rk-sum);
}
void dfs3(int x)
{
	root[x]=insert(root[fa[x]],1,cnt,s[x]);
	for(int i=e.head[x];i;i=e.nxt[i])
	{
		int to=e.ver[i];
		if(to==fa[x])	continue;
		dfs3(to);
	}
}
signed main()
{
	n=read();
	T=read();
	typ=read();
	for(int i=1;i<=n;i++)
		lsh[i]=s[i]=read();
	for(int i=1,x,y;i<n;i++)
	{
		x=read();
		y=read();
		e.add(x,y);
	}
	dfs1(1);
	dfs2(1,1);
	for(int i=1,m;i<=T;i++)
	{
		lsh[i+n]=q[i].dat=read();
		m=read();
		for(int j=1,x;j<=m;j++)
		{
			x=read();
			v[i].push_back(x);
		}
	}
	sort(lsh+1,lsh+n+T+1);
	cnt=unique(lsh+1,lsh+n+T+1)-lsh-1;
	for(int i=1;i<=n;i++)
		s[i]=lower_bound(lsh+1,lsh+cnt+1,s[i])-lsh;
	for(int i=1;i<=T;i++)
		q[i].dat=lower_bound(lsh+1,lsh+cnt+1,q[i].dat)-lsh;
	dfs3(1);
	for(int i=1;i<=T;i++)
	{
		for(int j=0;j<v[i].size();j++)
			v[i][j]=(v[i][j]-1+ans*typ)%n+1;
		ans=INF;
		int lca=v[i][0];
		for(int j=1;j<v[i].size();j++)
			lca=LCA(lca,v[i][j]);
		lca=fa[lca];
		for(int j=0;j<v[i].size();j++)
		{
			int num=v[i][j],minn,maxn,temp=INF;
			int rk=query_rank(root[lca],root[num],1,cnt,q[i].dat);
			if(rk<=1)	minn=query(root[lca],root[num],1,cnt,1);
			else	minn=query(root[lca],root[num],1,cnt,rk-1);
			if(rk>=tre[root[num]].dat-tre[root[lca]].dat)	maxn=query(root[lca],root[num],1,cnt,rk);
			else	maxn=query(root[lca],root[num],1,cnt,rk+1);
			if(rk>=1&&rk<=tre[root[num]].dat-tre[root[lca]].dat)
				temp=query(root[lca],root[num],1,cnt,rk);
			ans=min(ans,min(abs(lsh[q[i].dat]-lsh[minn]),abs(lsh[maxn]-lsh[q[i].dat])));
			if(temp!=INF)	ans=min(ans,abs(lsh[q[i].dat]-lsh[temp]));
		}
		printf("%lldn",ans);
	}
	return 0;
}

T3 f

解题思路

非常妙的一个题,有一个取一半的思想非常的重要。

对于 (xor) 的操作显然是应该拆位的,于是每一个数就会变成一个 01 串。

因此可以用 Tire 树进行维护,从而求出序列中每一位的逆序对的个数(描述的不太好,意会一下)

然后 (xor) 操作,直接是 0 就直接计算,是 1 的话就需要算入另一种情况的逆序对的个数。

但是,发现对于 (2^{30}) 的数据哪怕是 n 的复杂度也是搞不掉的,考虑把一个数”掰开”

于是我们可以发现对于大于 (2^{frac{k}{2}}) 的数,其实他的前 (dfrac{k}{2}) 位是在 (2^{frac{k}{2}}) 已经计算过了的,因此只需要再开一个数组记录后面几位的就好了。

然后我们发现时间复杂度还满足一个 log 的空余,诶,二分答案。。

逆序对的个数上的 f 数组是满足单调性的,因此对于逆序对个数进行二分。

如果小于当前扫描值的个数的数小于 p 那么就记录答案并查询右区间。

对于二分答案函数的处理就简单许多了,首先对于之前搞得两半的 f 数组分别排一下序。

然后这样就满足单调性了,接下来双指针(此双指针非彼双指针)分别扫两个数组。

这样就可以得到符合答案的值了,对于符合的值的下标的查询也是类似。

更改一下条件就可以了,对于等于 (f(ans)) 的都给记录下来,然后给下标排个序就好了。

c++ode

30pts 树状数组

#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=5e5+10;
int n,k,rank,s[N],q[N],a[N],f[N],id[N];
int tre[N],lsh[N],cnt;
int lowbit(int x)
{
	return x&(-x);
}
void Special_Judge1()
{
	printf("%lld %lld",rank-1,rank-1);
	exit(0);
}
bool comp(int x,int y)
{
	if(f[x]==f[y])	return x<y;
	return f[x]<f[y];
}
void add(int x,int num)
{
	for(int i=x;i<=n;i+=lowbit(i))
		tre[i]+=num;
}
int ask(int x)
{
	int sum=0;
	for(int i=x;i;i-=lowbit(i))
		sum+=tre[i];
	return sum;
}
void Special_Judge2()
{
	for(int x=0;x<(1<<k);x++)
	{
		memset(tre,0,sizeof(tre));
		id[x]=x;
		for(int i=1;i<=n;i++)
			lsh[i]=q[i]=(s[i]^x)+2;
		sort(lsh+1,lsh+n+1);
		cnt=unique(lsh+1,lsh+n+1)-lsh-1;
		for(int i=n;i>=1;i--)
		{
			q[i]=lower_bound(lsh+1,lsh+cnt+1,q[i])-lsh+1;
			f[x]+=ask(q[i]-1);
			add(q[i],1);
		}
	}
	sort(id+0,id+(1<<k),comp);
	printf("%lld %lld",f[id[rank-1]],id[rank-1]);
	exit(0);
}
void solve()
{
	int x=rank-1;
	for(int i=1;i<=n;i++)
		q[i]=s[i]^x;
	for(int i=2;i<=n;i++)
		for(int j=i-1;j>=1;j--)
			if(q[i]<q[j])
				a[i]++;
	for(int i=1;i<=n;i++)
		f[x]+=a[i];
	printf("%lld %lld",f[x],x);
}
signed main()
{
	n=read();
	k=read();
	rank=read();
	for(int i=1;i<=n;i++)
		s[i]=read();
	if(k==0)	Special_Judge1();
	if(k<=10)	Special_Judge2();
	solve();
	return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=5e5+10;
int n,rk,k,num,ans,s[N];
int all=1,cnt[N*40][2];
int top,sta[N*40];
struct Tire
{
	int dat,ch[2];
}tre[N*40];
struct Storage
{
	int dat,id;
}f1[N],f2[N];
void insert(int val)
{
	int rt=1;
	for(int i=k-1;i>=0;i--)
	{
		if(!tre[rt].ch[(val>>i)&1])	tre[rt].ch[(val>>i)&1]=++all;
		cnt[i][(val>>i)&1]+=tre[tre[rt].ch[((val>>i)&1)^1]].dat;
		tre[tre[rt].ch[(val>>i)&1]].dat++;
		rt=tre[rt].ch[(val>>i)&1];
	}
}
bool comp(Storage x,Storage y)
{
	if(x.dat!=y.dat)	return x.dat<y.dat;
	return x.id<y.id;
}
bool judge(int val)
{
	int total=0,sum=(1<<(k-k/2))-1;
	for(int i=0;i<(1<<(k/2));i++)
	{
		if(f1[i].dat>val)	break;
		while(sum>=0&&f1[i].dat+f2[sum].dat>=val)	sum--;
		total+=sum+1;
	}
	if(total<rk)	num=total;
	return total<rk;
}
int solve()
{
	int sum=(1<<(k-k/2))-1;
	for(int i=0;i<(1<<(k/2));i++)
	{
		if(f1[i].dat>ans)	break;
		while(sum>=0&&f1[i].dat+f2[sum].dat>ans)
			sum--;
		if(f2[sum].dat+f1[i].dat==ans)	sta[++top]=f2[sum].id*(1<<k/2)+f1[i].id;
	}
	sort(sta+1,sta+top+1);
	return sta[rk-num];
}
signed main()
{
	n=read();
	k=read();
	rk=read();
	for(int i=1;i<=n;i++)
	{
		s[i]=read();
		insert(s[i]);
	}
	for(int i=0;i<(1<<(k/2));i++)
	{
		for(int j=0;j<k/2;j++)
			f1[i].dat+=cnt[j][(i>>j)&1];
		f1[i].id=i;
	}
	for(int i=0;i<(1<<(k-k/2));i++)
	{
		for(int j=k/2;j<k;j++)
			f2[i].dat+=cnt[j][((i>>(j-k/2))&1)];
		f2[i].id=i;
	}
	sort(f1+0,f1+(1<<(k/2)),comp);
	sort(f2+0,f2+(1<<(k-k/2)),comp);
	int l=0,r=n*(n-1)/2;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(judge(mid))
		{
			l=mid+1;
			ans=mid;
		}
		else	r=mid-1;
	}
	printf("%lld %lld",ans,solve());
	return 0;
}

程序员灯塔
转载请注明原文链接:7.21考试总结(NOIP模拟22)[d·e·f]
喜欢 (0)