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

前言

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

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

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

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

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

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

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

T1 d

解题思路

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

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

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

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

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

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

code

暴力+特殊性质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("%lld\n",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("%lld\n",ans);
}
return 0;
}

T2 e

解题思路

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

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

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

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

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

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

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

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

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

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

code

暴力跳 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("%lld\n",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("%lld\n",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("%lld\n",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("%lld\n",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("%lld\n",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)\) 的都给记录下来,然后给下标排个序就好了。

code

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]的更多相关文章

  1. 2021.7.21考试总结[NOIP模拟22]

    终于碾压小熠了乐死了 T1 d 小贪心一波直接出正解,没啥好说的(bushi 好像可以主席树暴力找,但我怎么可能会呢?好像可以堆优化简单找,但我怎么可能想得到呢? 那怎么办?昨天两道单调指针加桶,我直 ...

  2. noip模拟22[d·e·f]

    noip模拟22 solutions 哈哈哈,这次暴力打满直接190,其实不到哈哈哈,187.. 这次的题暴力极其好打,但是正解确实不简单... 打了好久才改完这个题,改完的时候爽暴了 这些一个字母的 ...

  3. [考试总结]noip模拟22

    又发现模拟 \(22\) 的总结也咕掉了,现在补上它... 似乎又是gg的一场. 以为自己的部分分数打的很全,然而到后面发现自己的树剖打假了 \(\color{green}{\huge{\text{树 ...

  4. 2021.8.21考试总结[NOIP模拟45]

    T1 打表 由归纳法可以发现其实就是所有情况的总和. $\frac{\sum_{j=1}^{1<<k}(v_j-v_{ans})}{2^k}$ $code:$ 1 #include< ...

  5. 2021.9.21考试总结[NOIP模拟58]

    T1 lesson5! 开始以为是个无向图,直接不懂,跳去T2了. 之后有看了一眼发现可暴力,于是有了\(80pts\). 发现这个图是有拓扑序的,于是可以用拓扑排序找最长路径.先找原图内在最长路径上 ...

  6. 5.22考试总结(NOIP模拟1)

    5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...

  7. 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]

    6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...

  8. 5.23考试总结(NOIP模拟2)

    5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...

  9. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  10. [考试总结]noip模拟23

    因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...

随机推荐

  1. docker 应用篇————docker安装[二]

    前言 这其实是去年的一篇blog,忘了写了.本来我想先发一下理论的,但是水平.... 正文 如果你不熟悉linux,而是使用windows,那么你可以这样下载windows桌面版或者说你在这之前完全不 ...

  2. ImportError: Cannot load backend 'TkAgg' which requires the 'tk' interactive framework, as 'headless' is currently running

    MMdetection多卡训练常遇到的两个错误,百度无果,没解决,去github里mmdetection的issue模块搜索了一下找到正解. 这里记录一下,方便后者. 1️⃣ ImportError: ...

  3. Deep Learning on Graphs: A Survey第五章自动编码论文总结

    论文地址:https://arxiv.org/pdf/1812.04202.pdf 最近老师让我们读的一片论文,已经开组会讲完了,我负责的是第五章,图的自动编码,现在再总结一遍,便于后者研读.因为这篇 ...

  4. 【Nano Framework ESP32篇】WS2812 彩色灯带实验

    地球人皆知,许多物联网教程作者的心中都深爱着一灯大师,所以第一个例程总喜欢点灯,高级一点的会来个"一闪一闪亮晶晶".老周今天要扯的也是和灯有关的,但不单纯地点个灯,那样实在不好玩, ...

  5. ASP.NET CORE 框架揭秘读书笔记系列——命令行程序的创建(一)

    一.dotnet --info 查看本机开发环境 dotnet --info  会显示本机安装的SDK版本.运行时环境.运行时版本 二.利用命令行创建.NET项目 我们不仅可以利用脚手架模版创建各种类 ...

  6. 剑指offer11(Java)-旋转数组中的最小值(简单)

    题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转.请返回旋转数 ...

  7. 力扣180(MySQL)-连续出现的数字(中等)

    题目: 编写一个 SQL 查询,查找所有至少连续出现三次的数字. 返回的结果表中的数据可以按 任意顺序 排列. 查询结果格式如下面的例子所示: 解题思路: 原表数据: 方法一: 使用内连接(inner ...

  8. HarmonyOS NEXT应用开发—验证码布局

    介绍 本示例介绍如何使用Text组件实现验证码场景,并禁用对内容的选中.复制.光标. 效果图预览 使用说明 单击组件可弹出输入法 在进行验证码输入时,无法对中间单个数字进行更改,无法选中输入内容,无光 ...

  9. 5月25日,阿里云开源 PolarDB-X 将迎来重磅升级发布

    ​简介:2022年5月25日,阿里云开源 PolarDB-X 将升级发布新版本!PolarDB-X 从 2009 年开始服务于阿里巴巴电商核心系统, 2015 年开始对外提供商业化服务,并于 2021 ...

  10. KubeNode:阿里巴巴云原生 容器基础设施运维实践

    简介: 目前 KubeNode 已经覆盖了阿里巴巴集团的所有的 ASI 集群,接下来,将随着阿里巴巴集团"统一资源池"的项目,推进 KubeNode 覆盖更大的范围.更多的场景,让 ...