题目传送门(内部题67)


输入格式

第一行,三个整数$n$、$k$、$p$。
第二行,$n$个自然数,表示$\{a_i\}$。


输出格式

输出一行,两个自然数,表示$f(res)$、$res$。


样例

样例输入1:

4 3 5
2 0 3 7

样例输出1:

4 4

样例输入2:

2 2 1
2 0

样例输出2:

0 2


数据范围与提示

本题有$spj$,输出格式正确的情况下,仅回答正确$f(res)$、$res$中的一个可以获得$60\%$的分数(向下取整)。


题解

考虑怎样才能形成逆序对,或怎样才能让本身的逆序对消失。

设$a,b$,将其分解为二进制,我们只有改变其最高的不同位才能改变其大小关系;若对于其最高的不同位$a$为$0$,$b$为$1$,那么如果$xor$一个这一位是$1$的数,则其大小关系会改变,反之同理。

所以考虑$Trie$,将每一个$a_i$分解成二进制插入并计算贡献即可。

这样的算法是$55$分的。

考虑如何优化,部分正确提示了可以二分。

二分逆序对的个数即可,最后再用二分出来的值返回去找$res$即可。

时间复杂度:$\Theta(\log n^2\times 2^{\frac{k}{2}})$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int k;
long long n,p;
int trie[20000000][2],cnt=1;
long long sum[20000000][2],num[20000000];
long long ans;
long long val;
long long que[3000001];
pair<long long,int> f1[3000001],f2[3000001];
void insert(int x)
{
int p=0;
for(int i=k-1;i>=0;i--)
{
if(!trie[p][(x>>i)&1])trie[p][(x>>i)&1]=++cnt;
sum[i][(x>>i)&1]+=num[trie[p][((x>>i)&1)^1]];
p=trie[p][(x>>i)&1];
num[p]++;
}
}
bool judge(long long x)
{
long long res=0;
int fail=(1<<(k-k/2));
for(int i=0;i<(1<<(k/2))&&f1[i].first<=x;i++)
{
while(x-f1[i].first<=f2[fail-1].first&&fail)fail--;
res+=fail;
}
if(res<p){val=res;return 1;}
return 0;
}
long long getans()
{
int fail=(1<<(k-k/2))-1;
for(int i=0;i<(1<<(k/2))&&f1[i].first<=ans;i++)
{
long long x=ans-f1[i].first;
while(x<f2[fail].first&&fail>=0)fail--;
if(f2[fail].first==x)que[++que[0]]=f1[i].second+(1<<(k/2))*f2[fail].second;
}
sort(que+1,que+que[0]+1);
return que[p-val];
}
int main()
{
scanf("%lld%d%lld",&n,&k,&p);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
insert(x);
}
for(int i=0;i<(1<<(k/2));i++)
{
for(int j=0;j<(k/2);j++)f1[i].first+=sum[j][i>>j&1];
f1[i].second=i;
}
for(int i=0;i<(1<<(k-k/2));i++)
{
for(int j=0;j<(k-k/2);j++)f2[i].first+=sum[j+k/2][i>>j&1];
f2[i].second=i;
}
sort(f1,f1+(1<<(k/2)));
sort(f2,f2+(1<<(k-k/2)));
long long lft=0,rht=n*(n-1)/2;
while(lft<=rht)
{
long long mid=(lft+rht)>>1;
if(judge(mid)){lft=mid+1;ans=mid;}
else rht=mid-1;
}
printf("%lld %lld",ans,getans());
return 0;
}

rp++

[CSP-S模拟测试]:f(Trie树+二分答案+meet in middle+two pointers)的更多相关文章

  1. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  2. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  3. 2018.10.20 NOIP模拟 巧克力(trie树+dfs序+树状数组)

    传送门 好题啊. 考虑前面的32分,直接维护后缀trietrietrie树就行了. 如果#号不在字符串首? 只需要维护第一个#前面的字符串和最后一个#后面的字符串. 分开用两棵trie树并且维护第一棵 ...

  4. BZOJ3166 [Heoi2013]Alo 【可持久化trie树 + 二分 + ST表】

    题目 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , 如名字所见,到处充满了数学的谜题. 现在你拥有n颗宝石,每颗宝石 ...

  5. 4.15 省选模拟赛 编码 trie树 前缀和优化建图 2-sat

    好题 np. 对于20分 显然可以爆搜. 对于50分 可以发现每个字符串上的问号要么是0,要么是1.考虑枚举一个字符串当前是0还是1 这会和其他字符串产生矛盾. 所以容易 发现这是一个2-sat问题. ...

  6. [CSP-S模拟测试]:中间值(二分)

    题目背景 $Maxtir$喜欢序列的中间值. 题目传送门(内部题127) 输入格式 第一行输入两个正整数$n,m$,其中$m$是操作和询问次数. 接下来两行每行输入$n$个非负整数,每一行分别表示两个 ...

  7. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  8. 【bzoj2653】【middle】【主席树+二分答案】

    Description 一个长度为 n 的序列 a ,设其排过序之后为 b ,其中位数定义为 b[n/2] ,其中 a,b 从 0 开始标号 , 除法取下整. 给你一个长度为 n 的序列 s .回答 ...

  9. 洛谷P4632 [APIO2018] New Home 新家(动态开节点线段树 二分答案 扫描线 set)

    题意 题目链接 Sol 这题没有想象中的那么难,但也绝对不简单. 首先把所有的询问离线,按照出现的顺序.维护时间轴来处理每个询问 对于每个询问\((x_i, y_i)\),可以二分答案\(mid\). ...

随机推荐

  1. [转帖]是时候深入了解Linux的系统结构

    是时候深入了解Linux的系统结构   http://os.51cto.com/art/201905/596011.htm linux的体系结果 其实自己也知道 linus 做了一个 kernel 大 ...

  2. Mysql函数----控制流函数介绍

    MySQL有4个函数用来进行条件操作的,可以实现SQL的条件逻辑,允许开发者将一些应用程序业务逻辑转换到数据库后台.   MySQL控制流函数: 1.CASE WHEN[test1] THEN [re ...

  3. 基于bs4库的HTML标签遍历方法

    基于bs4库的HTML标签遍历方法 import requests r=requests.get('http://python123.io/ws/demo.html') demo=r.text HTM ...

  4. Skiing POJ 3037 很奇怪的最短路问题

    Skiing POJ 3037 很奇怪的最短路问题 题意 题意:你在一个R*C网格的左上角,现在问你从左上角走到右下角需要的最少时间.其中网格中的任意两点的时间花费可以计算出来. 解题思路 这个需要发 ...

  5. CCF1078奇怪的电梯

    这是一道dfs搜索题.(noi的题库测试数据有些水) 已知每一层的步数,有两个方向(上下),求解到达终点的最少操作数.拿到这个题就发现是一个Dfs,于是便套了模板写代码.Wa了三次才AC.核心是:1. ...

  6. 对C++拷贝构造函数的一点理解

    一. 什么是拷贝构造函数 先看一个简单的例子: #include <iostream> using namespace std; class CExample { private: int ...

  7. ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;

    参考来源:https://blog.csdn.net/yuxinha11/article/details/80090197 ENGINE=InnoDB不是默认就是这个引擎吗?——是的,如果不写也是ok ...

  8. Python 入门之 文件

    Python 入门之 文件 1.文件操作 找到文件位置 双击打开 进行一些操作 r-read(读) w-write(写) a-追加 rd--读字节 wd--清空写,写字节 ad --追加写(字节) r ...

  9. 使用 VS Code 搭建 TypeScript 开发环境

    使用 VS Code 搭建 TypeScript 开发环境 TypeScript 是 JavaScript 的超集,TypeScript 只是增强了 JavaScript 而非改变了 JavaScri ...

  10. 39. Combination Sum (Java)

    Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), fin ...