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

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

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

做法好神啊。关于异或的问题有一种常见做法,就是利用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)\)个因数,所以总的时间复杂度为\(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;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/9047757.html

时间: 2024-09-28 14:47:30

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

Codeforces Round #482 (Div. 2)D. Kuro and GCD and XOR and SUM+字典树

题目链接:D. Kuro and GCD and XOR and SUM 题意:两种操作:第一种给数组添加一个数,第二种输入x,k,s,要求从数组中找到一个数v,要求k能整除gcd(k,v);并且v<=s-x,然后异或v与k的异或值最大. 题解:对与k大于1的情况我们暴力枚举过去,k为1的特殊处理建一颗字典树,如果可以的满足条件的话,每次取值时往相反方向取. 1 #include<bits/stdc++.h> 2 #include <iostream> 3 #include

D. Kuro and GCD and XOR and SUM

Kuro is currently playing an educational game about numbers. The game focuses on the greatest common divisor (GCD), the XOR value, and the sum of two numbers. Kuro loves the game so much that he solves levels by levels day by day. Sadly, he's going o

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|gcd(a,x)$:现在需要找满足条件的$a$,它异或$x$的值最大.$x,k,s \leq 10^5$ 操作数$q \leq 10^5$ 这道题就是看你想到一个算法有没有去算算实际复杂度 我们发现,对于所有在$[1,10^5]$的$i$,$10^5$之内的$i$的倍数的个数和,并不是很大,只有$2*1

CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组(转)

转载自:http://www.cnblogs.com/icode-girl/p/5744409.html 题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum 题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有出现偶数次的数异或的值. 思路:容易想到,把区间内的所有的数都异或得到的是出现奇数次的数的值,然后再异或该区间内的所有出现过的数(每个数只统计一次),得到的ans了. 第一个问题:得到询问区间的

CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组

题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum 题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有出现偶数次的数异或的值. 思路:容易想到,把区间内的所有的数都异或得到的是出现奇数次的数的值,然后再异或该区间内的所有出现过的数(每个数只统计一次),得到的ans了. 第一个问题:得到询问区间的所有数的异或值,由 a[l~r] ^ a[0~(l-1)] = a[l~r] 可以用数组all_xor[i

【UVA12716】GCD和XOR

题意 输入整数n(1<=n<=3*107),有多少对整数(a,b)满足:1<=b<=a<=n,且gcd(a,b)=a XOR b.例如:n=7时,有4对:(3,2),(5,4),(6,4),(7,6) 分析 本题的主要想法就是找到一个沟通gcd(a,b)和a^b的桥梁 a^b≥a-b.口头化证明:假如二进制位上相同,那么都是0,加入二进制位上不同,前者一定是1,后者可能是1(1-0),也有可能借位导致数位减少(0-1) a-b≥gcd(a,b).由九章算术·更相减损术可得gc

GCD和XOR题解

由题意 我们要统计1~N中有多少二元组(a,b)满足gcd(a,b) ==a XOR b 首先有如下性质: 1.a XOR b >= a-b  (a >= b) 证明:(给个简单的证明 OI证明都不严谨的) 在二进制下 a XOR b :b某一位的1才对答案有影响,如果a那位为1那就相当于减,为0相当于加 a 减     b: 同样b的某一为的1才对答案影响,且a的那一位不管是0还是1,都是减 所以 a XOR b 一定 >= a-b 2. a - b >= gcd( a,b )

例题10-5 GCD等于XOR UVa12716

1.题目描述:点击打开链接 2.解题思路:本题能用的判断条件只有两个:(1)gcd(a,b)=c:(2)(a^b)=c:通过观察容易发现如果gcd(a,b)=(a^b)=c,那么c=a-b,因此可以事先枚举所有a的因数c,利用b=a-c计算b,然后只需验证是否满足(a^b)==c即可.但本题的数据太大,而且枚举约数不容易,因此可以利用约数c枚举倍数a,这样就会方便很多,打表的效率也足够高:而且,由于a=k*c,b=a-c=(k-1)*c,因此,必有gcd(a,b)=gcd(k*c,(k-1)*c

CF 1047 C. Enlarge GCD

传送门 [http://codeforces.com/contest/1047/problem/C] 题意 给你n个数,移除最少的数字是剩下的数字GCD大于初始GCD 思路 需要一点暴力的技巧,先求出初始GCD为g,并统计每个数字的个数这是减少复杂度的关键,令ans=0,我们从i=g+1开始枚举GCD为i的个数,进行统计每次更新ans=min(ans,n-cnt) 需要注意的是某个数的因子依然是那个数倍数的因子,如2 4 8.这样可以避免重复统计.具体看代码 代码 #include<bits/s