码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-05-17 23:16:24      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:trie   else   max   数组   name   printf   def   span   答案   

Brief Intro:

1操作:添加一个数

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

 

Algorithm:

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

 

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

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

 

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

为了满足另一个条件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即可

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

标签:trie   else   max   数组   name   printf   def   span   答案   

原文地址:https://www.cnblogs.com/newera/p/9053726.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!