• 【AFOI19】区间与除法


    前言

    利益相关:经常骗吃骗喝,也经常被出题人欺负QAQ。

    话说出题组的科技树点得有点歪(其实不是一般的歪)...要是认真觉得他们很综合性的话你就输啦!

    题解

    出题人上课摸鱼出得这题,给我口胡这题问我怎么做,然后我犯蠢了......我瞎扯了一通(自己都心虚的那种)准备水过去...

    但是在讨论的过程中,出题人说要用tire树,然后我就突然发现....\(d\)固定的情况下,根本不用去考虑怎么取最优方案来覆盖尽可能多的数,实际上,如果\(b_i\)\(a\)的原数,\(b_j\)也是\(a\)的原数的话,那么\(min(b_i,b_j)\)就是这三个数的公共原数....

    所以......直接枚举\(a_i\),然后依次除\(d\),若除的过程中\(a_i==b_j\),则取最小的\(b_j\),怎么快速找\(a_i==b_j\)呢?用出题人的方案或者数据结构的话太复杂了并且带个\(log\),把\(b_i\)排个序,\(a_i\)在除的过程中递减,\(b_j\)也随之递减,这样来找就行了,这一部分复杂度就是\(O(nlogn)\),取大一点的话其实是\(O(nm)\),但是\(m\)小于等于\(60\)

    剩下的,对于每一个\(a_i\)我们都找到了其唯一对应最小的\(b_j\)\(j\)小于等于\(60\),考虑状压,一个区间里面的状压或起来就是最优方案了,最后随便是\(st\)表还是线段树维护一下区间或值都可以。

    \(1.5s\)的话算良心了(嘿嘿)。

    
    #include <bits/stdc++.h>
    using namespace std;
    
    void readll(long long &an){
        char ch=getchar();an=0;
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')an=(an<<3)+(an<<1)+ch-'0',ch=getchar();
    }
    void read(int &an){
        char ch=getchar();an=0;
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')an=(an<<3)+(an<<1)+ch-'0',ch=getchar();
    }
    int n,m,d,q;
    long long b[65];
    long long a[500006];
    long long c[500005];
    long long t[2000005];
    void build(int l,int r,int id){
        if(l==r){
            t[id]=c[l];
            return ;
        }
        int mid=(l+r)/2;
        build(l,mid,id*2);
        build(mid+1,r,id*2+1);
        t[id]=t[id*2]|t[id*2+1];
    }
    
    long long query(int l,int r,int z,int y,int id){
        if(l==z&&r==y)return t[id];
        int mid=(l+r)/2;
        if(mid>=y)return query(l,mid,z,y,id*2);
        else if(mid<z)return query(mid+1,r,z,y,id*2+1);
        else return query(l,mid,z,mid,id*2)|query(mid+1,r,mid+1,y,id*2+1);
    }
    int get(long long x){
        int ans=0;
        while(x){
            ans++;
            x-=(x&(-x));
        }
        return ans;
    }
    
    int main(){
        read(n),read(m),read(d),read(q);
        for(int i=1;i<=n;i++){
            readll(a[i]);
        }
        for(int i=1;i<=m;i++){
            readll(b[i]);
        }
        sort(b+1,b+1+m);
        int rr=m;
        for(int i=1;i<=n;i++)
        {
            rr=m;
            while(a[i]){
                while(rr&&b[rr]>a[i])rr--;
                if(b[rr]==a[i])c[i]=(1ll<<(rr));
                a[i]/=d;
            }
        }
        build(1,n,1);
        for(int i=1;i<=q;i++){
            int l,r;
            read(l),read(r);
            printf("%d\n",get(query(1,n,l,r,1)));
        }
        return 0;
    }
    
  • 相关阅读:
    js正则表达式常见规则整理
    struts2标签 遍历map集合
    RabbitMQ面试问题
    vue基础学习
    flowableの历史查询
    flowableの日志打印
    flowableのID生成器
    flowableの流程发起人
    SpringBoot+Dubbo(XML配置方式)
    linux安装zookeeper伪分布式
  • 原文地址:https://www.cnblogs.com/redegg/p/11794133.html
Copyright © 2020-2023  润新知