[Codeforces 979D] Kuro and GCD and XOR and SUM

Brief Intro:

1操作:添加一个数

2操作:寻找一个数v,kiGCD(xi,v)xi+v≤si, 且v^xi最大

Algorithm:

以前做的关于异或和字符串的题目比较少,这题就当是补基础了吧

此题对v的限制条件很多,其中V、Xi异或值最大我们发现是一类经典问题

建立Trie树,贪心寻找答案即可

为了使答案满足kiGCD(xi,v),我们对1e5个数都各自建立一棵Trie树,其中存放这个数的所有倍数

扫描二维码关注公众号,回复: 906716 查看本文章

为了满足另一个条件V<=Si-Xi,我们对于每棵树上的每个节点维护一个min值,存放能到达此点的最小的数列中的数

这样也顺便解决了是K的倍数但不属于数列的数的问题(min数组初始化INF)

这样在查找时在满足min值<=Si-Xi的前提下贪心即可

Code:

#include <bits/stdc++.h>

using namespace std;

const int MAXN=1e5+10;
const int INF=1<<27;

bool mark[MAXN];
int q,tr[MAXN*20*20][2],mmin[MAXN*20*20],cnt=MAXN;  //对CNT的初始化很重要
vector<int> divi[MAXN];

void Update(int cur,int x)
{
    mmin[cur]=min(mmin[cur],x);
    for(int i=19;i>=0;i--)
    {
        bool d=(x&(1<<i));
        if(!tr[cur][d]) tr[cur][d]=cnt++;
        cur=tr[cur][d];mmin[cur]=min(mmin[cur],x);
    }
}

int Query(int x,int cur,int lim)
{
    if(mmin[cur]>lim) return -1;
    long long ret=0;
    for(int i=19;i>=0;i--)
    {
        bool d=(x&(1<<i));d=!d;
        if(mmin[tr[cur][d]]<=lim)  //查看是否满足条件
            cur=tr[cur][d],ret+=d*(1<<i);
        else
            cur=tr[cur][!d],ret+=(!d)*(1<<i);
    }
    return ret;
}

int main()
{
    scanf("%d",&q);
    for(int i=0;i<MAXN*20*20;i++) mmin[i]=INF;
    for(int i=1;i<MAXN;i++)
        for(int j=i;j<MAXN;j+=i)
            divi[j].push_back(i);
            
    for(int i=1;i<=q;i++)
    {
        int op,x,k,s;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&x);
            if(mark[x]) continue;
            mark[x]=true;
            for(int j=0;j<divi[x].size();j++) Update(divi[x][j],x);  //将个数的所有倍数都加进Trie中
        }
        else
        {
            scanf("%d %d %d",&x,&k,&s);
            if(x%k){puts("-1");continue;}
            printf("%d\n",Query(x,k,s-x));
        }
    }
    return 0;
}

Review:

1、异或最值   <------->    01Trie树

这两者之间的转换十分常用,需构建联系

Trie树的存储,一般使用Trie[MAXN][2]的方式更方便

其中01Trie树的MAXN要取大,要取到MAXN*20*20?(不确定,上界应该是MAXN*2^16?)

2、对于Trie树cnt初始化的问题

由于n棵Trie树已经有n个root,因此cnt应初始化为n+1!!!

3、当有时准确建图、建树要耗费太多时间时,考虑先全加进去,再通过极值初始化筛去不符合的点或边

ex:此处要想使得Trie树中X的倍数都来自于当前数列,不免会TLE

        因此可以先将全部倍数都加进去,而不在数列的倍数min值初始化为INF即可

猜你喜欢

转载自www.cnblogs.com/newera/p/9053726.html