CodeForces - 482D Kuro and GCD and XOR and SUM(01字典树)

链接:CodeForces - 482D Kuro and GCD and XOR and SUM

题意:

给一个空的集合aaa,共有q  (2q105)q\;(2\le q\le 10^5)q(2≤q≤105)次操作,分为以下222种操作

  • 1  ui1\;u_i1ui​:将uiu_iui​加入到集合aaa中  (1ui105)\;(1\le u_i\le 10^5)(1≤ui​≤105)
  • 2  xi  ki  si2\;x_i\;k_i\;s_i2xi​ki​si​:在集合aaa中找到一个数vvv,满足kigcd(xi,v),  xi+vsik_i|\gcd(x_i,v),\;x_i+v\le s_iki​∣gcd(xi​,v),xi​+v≤si​ 且 xivx_i\oplus vxi​⊕v最大,并输出vvv,若找不到,则输出1  (1xi,ki,si105)-1\;(1\le x_i,k_i,s_i\le10^5)−1(1≤xi​,ki​,si​≤105)


分析:

首先第一个条件kigcd(xi,v)k_i|\gcd(x_i,v)ki​∣gcd(xi​,v),也就是要求满足kixik_i|x_iki​∣xi​且kivk_i|vki​∣v,所以若不满足kixik_i|x_iki​∣xi​,可以直接输出1-1−1;

后两个条件:xi+vsix_i+v\le s_ixi​+v≤si​ 且 xivx_i\oplus vxi​⊕v最大,可以在字典树上进行查找,为保证xi+vsix_i+v\le s_ixi​+v≤si​(即vsixiv\le s_i-x_iv≤si​−xi​),可以再 设置一个变量min_val[u]min\_val[u]min_val[u],表示以uuu为根结点的子树内存储的最大值

这样每次查询 即要尽可能与xix_ixi​异或最大,还要保证对应子树的min_val[v]siximin\_val[v]\le s_i-x_imin_val[v]≤si​−xi​


其次,为满足kivk_i|vki​∣v,可以 对每一个kik_iki​值建一个01字典树(存储所有kik_iki​的倍数,即能被kik_iki​整除的数),对于新输入的uiu_iui​,要把 uiu_iui​插入到其所有因数对应的树中,找到所有因数的时间只需要O(ui)O(\sqrt {u_i})O(ui​​)。



以下代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e5+50;
const int INF=0x3f3f3f3f;
const int max_base=20;
int ch[maxn*200][2],val[maxn*200],min_val[maxn*200],tot;
struct bit_tire
{
    int root;
    void init()
    {
        ch[tot][0]=ch[tot][1]=0;
        val[tot]=0;
        min_val[tot]=INF;
        root=tot++;
    }
    void insert(int x)
    {
        int u=root;
        for(int i=max_base;i>=0;i--)
        {
            min_val[u]=min(x,min_val[u]);
            int c=(x>>i)&1;
            if(!ch[u][c])
            {
                ch[tot][0]=ch[tot][1]=0;
                val[tot]=0;
                min_val[tot]=INF;
                ch[u][c]=tot++;
            }
            u=ch[u][c];
        }
        min_val[u]=val[u]=x;
    }
    int query_max(int x,int y)   //查询该tire小于等于y的与x异或最大值
    {
        int u=root;
        for(int i=max_base;i>=0;i--)
        {
            int c=(x>>i)&1;
            if(ch[u][c^1]&&min_val[ch[u][c^1]]<=y)
                u=ch[u][c^1];
            else if(ch[u][c]&&min_val[ch[u][c]]<=y)
                u=ch[u][c];
            else
                return -1;
        }
        return val[u];
    }
}t[maxn];
void init()
{
    tot=1;
    for(int i=1;i<maxn;i++)
        t[i].init();
}
int main()
{
    init();
    int q,op,u,x,k,s;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&u);
            int k=(int)round(sqrt(u));
            for(int i=1;i<=k;i++)
            {
                if(u%i==0)
                {
                    t[i].insert(u);
                    t[u/i].insert(u);
                }
            }
        }
        else
        {
            scanf("%d %d %d",&x,&k,&s);
            if(x%k!=0)
                printf("-1\n");
            else
                printf("%d\n",t[k].query_max(x,s-x));
        }
    }
    return 0;
}

上一篇:最小表示法


下一篇:TextBox,RichTextBox设置行高