noip模拟22 solutions

哈哈哈,这次暴力打满直接190,其实不到哈哈哈,187.。

这次的题暴力极其好打,但是正解确实不简单。。。

打了好久才改完这个题,改完的时候爽暴了

这些一个字母的题就非常的迷人,题面很短,题目很难,但是拿分还是挺简单的

·

T1 d

就这个题考场一小时切掉,还是慢了点

这个就是一个排序加上,疯狂弹,

就是一个按照a排序,一个按照b排序

我们知道一定要删去小的,所以我们就。。。。

我们先删掉m个a中的a较小的矩形,然后我们就开始一个一个往回拿。

肯定我们要拿回来最大的,然后删掉一个b最小的,

我们这里要判断这个b有没有被删过,所以我们要加个while

如果删掉的a的id的b比当前的b小,那就直接删掉。。。

看代码

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
int T,n,m;
struct mtr{
int a,b,id;
bool operator < (mtr x)const{
if(b!=x.b)return b<x.b;
if(a!=x.a)return a<x.a;
return id<x.id;
}
}xa[N],xb[N];
ll ans;
bool via[N],vib[N];
bool cmpa(mtr x,mtr y){
if(x.a!=y.a)return x.a<y.a;
if(x.b!=y.b)return x.b<y.b;
return x.id<y.id;
}
bool cmpb(mtr x,mtr y){
if(x.b!=y.b)return x.b<y.b;
if(x.a!=y.a)return x.a<y.a;
return x.id<y.id;
}
signed main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++){
scanf("%d%d",&xa[i].a,&xa[i].b);
xa[i].id=i;xb[i]=xa[i];
}
sort(xa+1,xa+n+1,cmpa);
sort(xb+1,xb+n+1,cmpb);
//if(xb[1]<xb[2])cout<<"sb"<<endl;
for(re i=1;i<=m;i++)via[xa[i].id]=true;
int j=1;
while(via[xb[j].id])j++;
ans=1ll*xa[m+1].a*xb[j].b;
//cout<<xa[m+1].id<<" "<<xb[j].id<<endl;
for(re i=m;i>=1;i--){
via[xa[i].id]=false;
if(xa[i]<xb[j]){
ans=max(ans,1ll*xa[i+1].a*xb[j].b);
//cout<<xa[i].a<<" "<<xb[j].b<<endl;
continue;
}
j++;
while(via[xb[j].id])j++;
ans=max(ans,1ll*xa[i].a*xb[j].b);
}
printf("%lld\n",ans);
}
}


·

T2 e

考场暴力向上跳,跳出来80pts,为啥只有这么些分呢,因为没加快读,加上快读89,这是暴力的极限了

所以正解是主席树,以树上的关系为历史版本,他的爹是他的前一版本

然后直接找到共同的lca,分别找到k条链上的比r大的最小值,比r小的最大值

我们就找到了答案,所以我调了3个小时,为啥??因为我有一个数组越界了

为啥越界呢?因为我有一个计数器用了两次,加爆了,所以也不给我说段错误

只有一个错误的答案,导致我从昨天晚上一直调到了今天上午8:18

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n,q,typ,p[N*3],a[N];
int to[N*2],nxt[N*2],head[N],rp;
int lsh[N*4],lh;
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
struct ZXS{
int ls[N*80],rs[N*80];
int siz[N*80];
int seg;
void ins(int pre,int &x,int l,int r,int pos){
x=++seg;
siz[x]=siz[pre];
siz[x]+=1;
if(l==r)return ;
int mid=l+r>>1;
if(pos<=mid)rs[x]=rs[pre],ins(ls[pre],ls[x],l,mid,pos);
else ls[x]=ls[pre],ins(rs[pre],rs[x],mid+1,r,pos);
return ;
}
int query_min(int pre,int x,int l,int r,int ql,int qr){
//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<siz[ls[x]]<<" "<<siz[ls[pre]]<<endl;
//if(!x)return -1;
//if(ql>r||qr<l)return -1;
if(l==r)return l;
int mid=l+r>>1,ret=-1;
if(ls[x]!=ls[pre]&&ql<=mid)ret=query_min(ls[pre],ls[x],l,mid,ql,qr);
if(rs[x]!=rs[pre]&&qr>mid&&ret==-1)ret=query_min(rs[pre],rs[x],mid+1,r,ql,qr);
return ret;
}
int query_max(int pre,int x,int l,int r,int ql,int qr){
//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
//if(!x)return -1;
//if(ql>r||qr<l)return -1;
if(l==r)return l;
int mid=l+r>>1,ret=-1;
if(rs[x]!=rs[pre]&&qr>mid)ret=query_max(rs[pre],rs[x],mid+1,r,ql,qr);
if(ls[x]!=ls[pre]&&ql<=mid&&ret==-1)ret=query_max(ls[pre],ls[x],l,mid,ql,qr);
return ret;
}
}zxs;
int rt[N],ans;
int dfn[N],cnt,idf[N],fa[N];
int siz[N],son[N],top[N],dep[N];
void dfs1(int x){
siz[x]=1;son[x]=0;
a[x]=lower_bound(lsh+1,lsh+lh+1,a[x])-lsh;
zxs.ins(rt[fa[x]],rt[x],1,lh,a[x]);
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x])continue;
fa[y]=x;dep[y]=dep[x]+1;
dfs1(y);siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs2(int x,int f){
dfn[x]=++cnt;idf[cnt]=x;
top[x]=f;
if(son[x])dfs2(son[x],f);
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==son[x]||y==fa[x])continue;
dfs2(y,y);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int r[N*3],k[N*3],ll[N*3],rr[N*3],tot;
signed main(){
scanf("%d%d%d",&n,&q,&typ);
for(re i=1;i<=n;i++)scanf("%d",&a[i]),lsh[++lh]=a[i];
for(re i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
add_edg(x,y);add_edg(y,x);
}
//for(re i=1;i<=n;i++)cout<<rt[i]<<" ";
for(re i=1;i<=q;i++){
scanf("%d%d",&r[i],&k[i]);
ll[i]=tot+1;
for(re j=1;j<=k[i];j++)scanf("%d",&p[++tot]);
rr[i]=tot;
lsh[++lh]=r[i];
}
sort(lsh+1,lsh+lh+1);
lh=unique(lsh+1,lsh+lh+1)-lsh-1;
//cout<<"lh :"<<lh<<endl;
dfs1(1);dfs2(1,1);
//for(re i=1;i<=n;i++)cout<<rt[i]<<" ";
int lans=0;
for(re i=1;i<=q;i++){
int lca=0;ans=0x3f3f3f3f;
//cout<<k[i]<<endl;
for(re j=ll[i];j<=rr[i];j++){
p[j]=(p[j]-1+lans*typ)%n+1;
if(j==ll[i])lca=p[j];
else lca=LCA(lca,p[j]);
//cout<<j<<" "<<"finish lca"<<endl;
}
//cout<<i<<" lca: "<<lca<<endl;
//cout<<i<<" "<<"finish lca"<<endl;
r[i]=lower_bound(lsh+1,lsh+lh+1,r[i])-lsh;
for(re j=ll[i];j<=rr[i];j++){
int tmp1=zxs.query_min(rt[lca],rt[p[j]],1,lh,r[i],lh);
//cout<<"finish min"<<" "<<j<<endl;
int tmp2=zxs.query_max(rt[lca],rt[p[j]],1,lh,1,r[i]);
//cout<<"finish max"<<" "<<j<<endl;
//cout<<r[i]<<" "<<tmp1<<" "<<tmp2<<" "<<j<<endl;
//cout<<i<<" "<<"finish query"<<" "<<p[j]<<endl;
if(tmp1!=-1)ans=min(ans,lsh[tmp1]-lsh[r[i]]);
if(tmp2!=-1)ans=min(ans,lsh[r[i]]-lsh[tmp2]);
}
ans=min(ans,abs(lsh[a[lca]]-lsh[r[i]]));
lans=ans;
printf("%d\n",ans);
}
}


·

T3 f

这个题直接告诉我一个消息,遇到和位运算有关的东西,首先想trie树

这个题也是在trie树上实现的,首先我们发现,每一位的贡献是互不影响的

一个数对答案的贡献就是他对应的子树的另外那颗子树的大小,0就是1,1就是0

为什么,我们按照位置顺序插入,那么后插入的如果值比先插入的小

他们一定会有一个最高不一样的位,我们就在这一位统计贡献

然而我们不可以每次都重新插入一遍,你会比树状数组T的更惨

我们发现,如果xor的那个x某一位是1的话,就是把这两颗子树交换一下,那么此时的贡献就是原树上在1找0的个数

如果是0,那就反过来。如此我们就可以\(O(2^klogn)\)解决掉前几个点

但是还不够,我们还要继续优化,meet in the middle 对,没错,从中间拆开

分为前\(\frac{k}{2}\)个和后\(\frac{k}{2}\)个,这样的话,复杂度就在可控范围内了

第一问,我们二分这个逆序对个数,判断函数里面是一个双指针,这个自己看代码吧,因为解释不清楚

第二问和第一问一样,也是双指针,只不过这次我们统计相等的情况而不是小于等于,这里开个vector来存有那些数可以到这个大小

最后输出就完事了。。。

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define fi first
#define se second
const int N=5e5+5;
int n,k,p,a[N];
int k1,k2,s1,s2;
ll gx[35][2],ans1,ans2;
int rt;
struct TRIE{
ll siz[N*35];
int seg;
int son[N*35][2];
void ins(int &x,int v,int dep){//dep 30 less
if(!x)x=++seg;
siz[x]++;
if(dep<0)return ;
int tmp=v>>dep&1;
gx[dep][tmp]+=siz[son[x][tmp^1]];
ins(son[x][tmp],v,dep-1);
}
}t;
pair<long long,int> f1[N*2],f2[N*2];
int check(ll x){
ll ret=0,j=s2;
for(re i=1;i<=s1;i++){
while(f2[j].fi+f1[i].fi>x&&j>0)j--;
ret+=j;
}
return ret;
}
vector<int> ji;
signed main(){
scanf("%d%d%d",&n,&k,&p);
if(k==0){
cout<<"0 0"<<endl;
return 0;
}
for(re i=1;i<=n;i++)scanf("%d",&a[i]),t.ins(rt,a[i],30);
k1=k>>1;k2=k-k1;
s1=1<<k1;s2=1<<k2;
for(re i=0;i<(1<<k1);i++){
ll tmp=0;
for(re j=0;j<k1;j++)
tmp+=gx[j][i>>j&1];
f1[i+1].fi=tmp;
f1[i+1].se=i;
}
//ll as=f1[1];
sort(f1+1,f1+s1+1);
for(re i=0;i<(1<<k2);i++){
ll tmp=0;
for(re j=0;j<k2;j++)
tmp+=gx[j+k1][i>>j&1];
f2[i+1].fi=tmp;
f2[i+1].se=i;
}
//cout<<as+f2[1]<<endl;
sort(f2+1,f2+s2+1);
ll l=0,r=1ll*n*(n-1)/2;
while(l<r){
ll mid=l+r>>1;
if(check(mid)<p)l=mid+1;
else r=mid;
}ans1=l;
//cout<<"finish first"<<" "<<ans1<<endl;
ll bas=check(ans1-1),j=s2;
//cout<<bas<<endl;
for(re i=1;i<=s1;i++){
int tmp;
while(f2[j].fi+f1[i].fi>ans1)j--;
tmp=j;
while(f2[j].fi+f1[i].fi==ans1&&j>0){
ji.push_back(f1[i].se+(f2[j].se<<k1));
j--;
}
j=tmp;
}
sort(ji.begin(),ji.end());
ans2=ji[p-bas-1];
printf("%lld %lld",ans1,ans2);
}


noip模拟22[d·e·f]的更多相关文章

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

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

  2. NOIP 模拟 $22\; \rm f$

    题解 \(by\;zj\varphi\) 对于一个数,如果它二进制下第 \(i\) 位为 \(1\),那么 \(\rm x\) 在这一位选 \(1\) 的贡献就是和它不同的最高为为 \(i\) 的数的 ...

  3. NOIP模拟22「d·e·f」

    T1:d   枚举.   现在都不敢随便打枚举了.   实际上我们只关注最后留下的矩阵中最小的长与宽即可.   所以我们将所有矩阵按a的降序排列.   从第\(n-m\)个开始枚举.   因为你最多拿 ...

  4. Noip模拟22 2021.7.21

    T1 d 简化题意就是找到相对平均长宽的偏移量较大的矩形给他删掉 可以说是个贪心,按照a,b分别为第一关键字排序 然后假装删去要求的那么多个按a排序的较小的,然后再去b中, 找到 删去的a中的那几个矩 ...

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

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

  6. NOIP模拟22

    T1d 一道垃圾贪心,写个堆优化或者桶就行 1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; ...

  7. NOIP 模拟 $22\; \rm e$

    题解 对于这个 \(abs\) 就是求大于 \(r\) 的最小值,小于 \(r\) 的最大值,建权值线段树或平衡树. 因为是 \(k\) 个点的联通块,就是求它们的 \(lca\) 到它们的链,可持久 ...

  8. NOIP 模拟 $22\; \rm d$

    题解 很好的贪心题 考虑去掉的矩形一定是几个 \(a\) 最小的,几个 \(b\) 最小的,枚举去掉几个 \(a\),剩下的去掉 \(b\) 先对 \(a\) 排序,用小根堆维护 \(b\) ,记录哪 ...

  9. NOIP模拟 22

    剧情回放:xuefeng:考场上你们只打暴力不打正解,我不满意! skyh:考场怒切T2以表明自己拥护xuefeng的决心 BoboTeacher:这场考试就没想让你们上100 神犇skyh:(笑而不 ...

随机推荐

  1. [202103] Interview Summary

    整理 2021 March「偷」到的算法题. 题目: 阿里:https://codeforces.com/contest/1465/problem/C 字节:输出 LCS Jump Trading:给 ...

  2. Python上下文管理器你学会了吗?

    ​什么是上下文管理器 对于像文件操作.连接数据库等资源管理的操作,我们必须在使用完之后进行释放,不然就容易造成资源泄露.为了解决这个问题,Python的解决方式便是上下文管理器.上下文管理器能够帮助你 ...

  3. 使用Hugo框架搭建博客的过程 - 部署

    前言 完成前期的准备工作后,在部署阶段需要配置服务器或对象存储服务. 对象存储和服务器对比 对象存储平台 国内有阿里云OSS.腾讯COS.又拍云.七牛云等.国外有Github Pages.Netlif ...

  4. windows下命令

    shutdown -s -t 0 关机 shutdown -r -t 0 重启 mstsc 远程桌面 notepad 记事本 regedit 注册表 calc 计算器 start applicatio ...

  5. Java刷题常用API

    目录 输入输出 快速查看 最大最小值 string stringbuilder 集合 map queue stack set 优先队列 PriorityQueue (Heap) 数组 静态数组 动态数 ...

  6. 谷粒商城--分布式基础篇(P1~P27)

    谷粒商城--分布式基础篇P1~P27 去年3月份谷粒商城分布式基础.进阶.高级刚出的时候就开始学了,但是中途因为一些事就中断了,结果一直到现在才有时间重新开始学,看到现在网上这么多人都学完了,确实感觉 ...

  7. 史上最全的Nginx配置文档

    Nginx是一个异步框架的Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存.该软件由Igor Sysoev 创建,并于2004年首次公开发布.同名公司成立于2011年,以提供支持.Ngi ...

  8. CQOI 2021 游记

    CQOI 2021 游记 Stage -1 \(\texttt{NOIP}\) 考的比较爆炸所以觉得自己没啥指望了. Stage 0

  9. 【多线程】C++ 互斥锁(mutex)的简单原理分析

    多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序.一般情况下,分为两种类型的多任务处理:基于进程和基于线程. 1)基于进程的多任务处理是程序的并发执行. 2)基于线程 ...

  10. Vue权限路由实现总结

    前言 年前完工了做了半年的铁路后台管理系统,系统整体业务比较复杂,这也是我到公司从 0 到 1 的 一个完整系统实践,做这个系统过程中踩了不少坑,也学到了很多. 做完这个系统没多久,紧接着又一个系统来 ...