CF 979D Kuro and GCD and XOR and SUM(异或 Trie)

给出q(<=1e5)个操作。操作分两种,一种是插入一个数u(<=1e5),另一种是给出三个数x,k,s(<=1e5),求当前所有u中满足,k|u,x+u<=s,且\(x\oplus u\)最大的u。

做法好神啊。关于异或的问题有一种常见做法,就是利用01trie来查找在一堆数里面,哪个数与x的异或值最大。这道题就是这个思路。如果去掉k必须整除v这个条件,那么就转化成了上一个问题(只不过有最大值的限制,怎么解决具体看代码)。

这道题的做法非常神奇。我们建1e5个Trie,第i个Trie中插入值为i的倍数的数。这样,查询x,k,s时,只要查询第k个Trie即可,因为里面的数一定满足k|v。插入时要遍历u的所有因数si,然后将u插入第si个Trie。

注意,异或运算是在尾部对齐的,但是要在Trie上贪心,所以必须在插入和查询的数前补零,使他们长度相同。

分析一波复杂度:

  • 预处理:我们需要预处理出u的因数。u的最大值为Max=1e5。用类似筛法的方法,时间复杂度是\(O(Max(1+\frac{1}{2}+\frac{1}{3}...+\frac{1}{Max}))=O(MaxInMax)\)。
  • 查询:就是Trie上的查询,总时间复杂度为\(O(qlog_2Max)\)。
  • 插入:一个数最多只有\(log_2(Max)\)个因数(\(2*10^9\)内因数最多的数之一是1837836000,有1536个因数),所以总的时间复杂度为\(O(qlog^2_2(Max))\)。
  • 空间复杂度:最多插入\(qlog_2(Max)\)个数,因此空间复杂度为\(qlog_2^2(Max)\)。

果然只能膜拜膜拜。

#include <cstdio>
#include <vector>
using namespace std; const int maxnum=1e5+5, maxq=1e5+5, maxn=maxq*17*17, INF=1e9;
//maxnum指插入的数的最大值 maxq指查询的最多数目
//maxn指结点的最多数目(=maxq*插入几个trie*插入数的二进制长度)
int s[maxn][2], minm[maxn], v[maxn], tot;
int q, root[maxnum], use[maxnum];
vector<int> div[maxnum]; void init(){
for (int i=1; i<maxnum; ++i)
for (int j=i; j<maxnum; j+=i)
div[j].push_back(i);
} //把x插到对应的trie里,注意维护子树中的最小数 l:处理到从左到右第几位
void insert(int &now, int x, int l){
if (!now){ now=++tot; minm[now]=INF; }
minm[now]=min(minm[now], x);
if (l==-1){ v[now]+=x; return; }
if ((x>>l)&1) insert(s[now][1], x, l-1);
else insert(s[now][0], x, l-1);
} //要找到v<=lim,并且x^v尽量大(贪心)。函数返回v
//注意由于没有删除操作,路径底下一定有点。
int query(int now, int x, int lim, int l){ //l:第几位
if (l==-1) return v[now];
int s0=s[now][0], s1=s[now][1];
if (!s0||minm[s0]>lim) return query(s[now][1], x, lim, l-1);
if (!s1||minm[s1]>lim) return query(s[now][0], x, lim, l-1);
if ((x>>l)&1) return query(s[now][0], x, lim, l-1);
else return query(s[now][1], x, lim, l-1);
} int main(){
init();
scanf("%d", &q); int op, x, k, s;
for (int i=0; i<q; ++i){
scanf("%d", &op);
if (op==1){
scanf("%d", &x);
if (use[x]) continue; use[x]=1;
for (int j=0; j<div[x].size(); ++j)
insert(root[div[x][j]], x, 18);
} else {
scanf("%d%d%d", &x, &k, &s);
if (x%k||!minm[root[k]]||minm[root[k]]+x>s) puts("-1"); //注意可能没有一个数
else printf("%d\n", query(root[k], x, s-x, 18)); //保证一定有解
}
}
return 0;
}

CF 979D Kuro and GCD and XOR and SUM(异或 Trie)的更多相关文章

  1. Codeforces 979 D. Kuro and GCD and XOR and SUM(异或和,01字典树)

    Codeforces 979 D. Kuro and GCD and XOR and SUM 题目大意:有两种操作:①给一个数v,加入数组a中②给出三个数x,k,s:从当前数组a中找出一个数u满足 u ...

  2. codeforces 979D Kuro and GCD and XOR and SUM

    题意: 给出两种操作: 1.添加一个数字x到数组. 2.给出s,x,k,从数组中找出一个数v满足gcd(x,k) % v == 0 && x + v <= s && ...

  3. CodeForces 979 D Kuro and GCD and XOR and SUM

    Kuro and GCD and XOR and SUM 题意:给你一个空数组. 然后有2个操作, 1是往这个数组里面插入某个值, 2.给你一个x, k, s.要求在数组中找到一个v,使得k|gcd( ...

  4. D. Kuro and GCD and XOR and SUM

    Kuro is currently playing an educational game about numbers. The game focuses on the greatest common ...

  5. CodeForces979D:Kuro and GCD and XOR and SUM(Trie树&指针&Xor)

    Kuro is currently playing an educational game about numbers. The game focuses on the greatest common ...

  6. cf round 482D Kuro and GCD and XOR and SUM

    题意: 开始有个空集合,现在有两种操作: $(1,x)$:给集合加一个数$x$,$x \leq 10^5$; $(2,x,k,s)$:在集合中找一个$a$,满足$a \leq s-x$,而且$k|gc ...

  7. Codeforces Round #482 (Div. 2) : Kuro and GCD and XOR and SUM (寻找最大异或值)

    题目链接:http://codeforces.com/contest/979/problem/D 参考大神博客:https://www.cnblogs.com/kickit/p/9046953.htm ...

  8. cf979d Kuro and GCD and XOR and SUM

    set做法 正解是trie-- 主要是要学会 \(a\ \mathrm{xor}\ b \leq a+b\) 这种操作 #include <iostream> #include <c ...

  9. 【Trie】【枚举约数】Codeforces Round #482 (Div. 2) D. Kuro and GCD and XOR and SUM

    题意: 给你一个空的可重集,支持以下操作: 向其中塞进一个数x(不超过100000), 询问(x,K,s):如果K不能整除x,直接输出-1.否则,问你可重集中所有是K的倍数的数之中,小于等于s-x,并 ...

随机推荐

  1. php 数据处理--合并,拆分,追加,去重

    1. 合并数组 array_merge()函数将数组合并到一起,返回一个联合的数组.所得到的数组以第一个输入数组参数开始,按后面数组参数出现的顺序依次迫加. 示例代码: <?php $arr = ...

  2. 【BZOJ 4709】柠檬 斜率优化dp+单调栈

    题意 给$n$个贝壳,可以将贝壳分成若干段,每段选取一个贝壳$s_i$,这一段$s_i$的数目为$num$,可以得到$num^2\times s_i$个柠檬,求最多能得到几个柠檬 可以发现只有在一段中 ...

  3. 2_flyweight, 轻量化模式

    ### instanced rendering. send shared data to gpu just once mesh, texture, leaves push every instance ...

  4. python实现Deque

    1 Deque定义 deque(也称为双端队列)是与队列类似的项的有序集合.它有两个端部,首部和尾部,并且项在集合中保持不变.deque 不同的地方是添加和删除项是非限制性的.可以在前面或后面添加新项 ...

  5. WC2010 BZOJ1758 重建计划_长链剖分

    题目大意: 求长度$\in [L,U]$的路径的最大边权和平均值. 题解 首先二分就不用说了,分数规划大家都懂. 这题有非常显然的点分治做法,但还是借着这个题学一波长链剖分. 其长链剖分本身也没啥,就 ...

  6. ACM学习历程—HDU4969 Just a Joke(物理题)

    Just a Joke Description Here is just a joke, and do not take it too seriously. Guizeyanhua is the pr ...

  7. POJ1703(2集合并查集)

    Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 39402   Accepted: ...

  8. RESTEasy入门学习

    RESTEasy是JBoss的开源项目之一,是一个RESTful Web Services框架.RESTEasy的开发者Bill Burke同时也是JAX-RS的J2EE标准制定者之一.JAX-RS是 ...

  9. Telnet用不了怎么办

    配置了几天的Oracle数据库,忙坏我了,遇到无数问题,其中一个就是Telnet无法使用: 经过检查发现,其实是这个软件没有安装,取程序里面找到之后,加装这个组件,完成安装. 但是还是不能用,发现服务 ...

  10. shell解决DOS攻击生产案例

    解决DOS攻击生产案例企业实战题5:请用至少两种方法实现!写一个脚本解决DOS攻击生产案例.提示:根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100,即调用防火墙命令封 ...