noip模拟22[d·e·f]
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]的更多相关文章
- [考试总结]noip模拟22
又发现模拟 \(22\) 的总结也咕掉了,现在补上它... 似乎又是gg的一场. 以为自己的部分分数打的很全,然而到后面发现自己的树剖打假了 \(\color{green}{\huge{\text{树 ...
- NOIP 模拟 $22\; \rm f$
题解 \(by\;zj\varphi\) 对于一个数,如果它二进制下第 \(i\) 位为 \(1\),那么 \(\rm x\) 在这一位选 \(1\) 的贡献就是和它不同的最高为为 \(i\) 的数的 ...
- NOIP模拟22「d·e·f」
T1:d 枚举. 现在都不敢随便打枚举了. 实际上我们只关注最后留下的矩阵中最小的长与宽即可. 所以我们将所有矩阵按a的降序排列. 从第\(n-m\)个开始枚举. 因为你最多拿 ...
- Noip模拟22 2021.7.21
T1 d 简化题意就是找到相对平均长宽的偏移量较大的矩形给他删掉 可以说是个贪心,按照a,b分别为第一关键字排序 然后假装删去要求的那么多个按a排序的较小的,然后再去b中, 找到 删去的a中的那几个矩 ...
- 2021.7.21考试总结[NOIP模拟22]
终于碾压小熠了乐死了 T1 d 小贪心一波直接出正解,没啥好说的(bushi 好像可以主席树暴力找,但我怎么可能会呢?好像可以堆优化简单找,但我怎么可能想得到呢? 那怎么办?昨天两道单调指针加桶,我直 ...
- NOIP模拟22
T1d 一道垃圾贪心,写个堆优化或者桶就行 1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; ...
- NOIP 模拟 $22\; \rm e$
题解 对于这个 \(abs\) 就是求大于 \(r\) 的最小值,小于 \(r\) 的最大值,建权值线段树或平衡树. 因为是 \(k\) 个点的联通块,就是求它们的 \(lca\) 到它们的链,可持久 ...
- NOIP 模拟 $22\; \rm d$
题解 很好的贪心题 考虑去掉的矩形一定是几个 \(a\) 最小的,几个 \(b\) 最小的,枚举去掉几个 \(a\),剩下的去掉 \(b\) 先对 \(a\) 排序,用小根堆维护 \(b\) ,记录哪 ...
- NOIP模拟 22
剧情回放:xuefeng:考场上你们只打暴力不打正解,我不满意! skyh:考场怒切T2以表明自己拥护xuefeng的决心 BoboTeacher:这场考试就没想让你们上100 神犇skyh:(笑而不 ...
随机推荐
- [202103] Interview Summary
整理 2021 March「偷」到的算法题. 题目: 阿里:https://codeforces.com/contest/1465/problem/C 字节:输出 LCS Jump Trading:给 ...
- Python上下文管理器你学会了吗?
什么是上下文管理器 对于像文件操作.连接数据库等资源管理的操作,我们必须在使用完之后进行释放,不然就容易造成资源泄露.为了解决这个问题,Python的解决方式便是上下文管理器.上下文管理器能够帮助你 ...
- 使用Hugo框架搭建博客的过程 - 部署
前言 完成前期的准备工作后,在部署阶段需要配置服务器或对象存储服务. 对象存储和服务器对比 对象存储平台 国内有阿里云OSS.腾讯COS.又拍云.七牛云等.国外有Github Pages.Netlif ...
- windows下命令
shutdown -s -t 0 关机 shutdown -r -t 0 重启 mstsc 远程桌面 notepad 记事本 regedit 注册表 calc 计算器 start applicatio ...
- Java刷题常用API
目录 输入输出 快速查看 最大最小值 string stringbuilder 集合 map queue stack set 优先队列 PriorityQueue (Heap) 数组 静态数组 动态数 ...
- 谷粒商城--分布式基础篇(P1~P27)
谷粒商城--分布式基础篇P1~P27 去年3月份谷粒商城分布式基础.进阶.高级刚出的时候就开始学了,但是中途因为一些事就中断了,结果一直到现在才有时间重新开始学,看到现在网上这么多人都学完了,确实感觉 ...
- 史上最全的Nginx配置文档
Nginx是一个异步框架的Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存.该软件由Igor Sysoev 创建,并于2004年首次公开发布.同名公司成立于2011年,以提供支持.Ngi ...
- CQOI 2021 游记
CQOI 2021 游记 Stage -1 \(\texttt{NOIP}\) 考的比较爆炸所以觉得自己没啥指望了. Stage 0
- 【多线程】C++ 互斥锁(mutex)的简单原理分析
多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序.一般情况下,分为两种类型的多任务处理:基于进程和基于线程. 1)基于进程的多任务处理是程序的并发执行. 2)基于线程 ...
- Vue权限路由实现总结
前言 年前完工了做了半年的铁路后台管理系统,系统整体业务比较复杂,这也是我到公司从 0 到 1 的 一个完整系统实践,做这个系统过程中踩了不少坑,也学到了很多. 做完这个系统没多久,紧接着又一个系统来 ...