zoukankan      html  css  js  c++  java
  • bzoj3136

    Description

    给定m个素数和Q个询问。每个询问有n个人,每次操作可以任意选择其中的一个素数p(素数可以重复使用),然后去掉剩余人数 mod p个人。对于每个询问,我们想知道,至少需要多少步操作才能去掉所有人。

    Input

    第一行:素数个数m和询问个数Q1 <= m <= 100 0001 <= Q <= 100 000)第二行:m个素数pi (2 <= pi <= 10 000 000)下面Q行:n (1 <= n <= 10 000 000

    Output

    Q行答案。如果无解,输出oo

    设f[n]为n的答案,则f[0]=0,f[i]单调非降,f[n]=1+f[v],其中v为某个素数pi的整数倍且v<n<v+pi,当n>=所有给定素数之积则无解

    从小到大枚举n,维护pi不超过n的最大倍数,记录t[x]表示值为x的合法倍数个数,以及对每个数x用链表维护当前哪些质数的合法倍数在这个位置

    最坏情况下素数倍数更新次数大约在3e7

    #include<cstdio>
    #include<algorithm>
    char buf[5000007],*ptr=buf-1;
    int n,Q,x,f[10000007],ps[100007],qs[100007],mq=0;
    int t[10000007],p=0;
    int e0[10000007],enx[100007];
    long long lcm=1;
    int _(){
        int x=0,c=*++ptr;
        while(c<48)c=*++ptr;
        while(c>47)x=x*10+c-48,c=*++ptr;
        return x;
    }
    void maxs(int&a,int b){if(a<b)a=b;}
    int main(){
        fread(buf,1,5000000,stdin);
        n=_();Q=_();
        for(int i=1;i<=n;++i)ps[i]=_();
        for(int i=1;i<=n&&lcm<=10000000;++i)lcm*=ps[i];
        for(int i=0;i<Q;++i)maxs(mq,qs[i]=_());
        if(lcm-1<mq)mq=lcm-1;
        for(int i=1;i<=n;++i)e0[ps[i]]=i;
        t[0]=n;
        for(int i=1;i<=mq;++i){
            for(int e=e0[i],nx,w;e;e=nx){
                nx=enx[e];
                --t[i-ps[e]];
                ++t[i];
                int j=i+ps[e];
                if(j<=mq)enx[e]=e0[j],e0[j]=e;
            }
            while(!t[p])++p;
            f[i]=1+f[p];
        }
        for(int i=0;i<Q;++i){
            if(qs[i]<lcm)printf("%d
    ",f[qs[i]]);
            else puts("oo");
        }
        return 0;
    }
  • 相关阅读:
    [LUOGU] 1364 医院设置
    [POJ] 3278 Catch That Cow
    [OpenJudge] 2727 仙岛寻药
    [POJ] 2386 Lake Counting
    [POJ]1118 Lining up
    [LUOGU]1141 01迷宫
    [POJ]1111 Image Perimeters
    python之路——初识函数
    python----------文件操作
    Python中的split()函数的用法
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6067117.html
Copyright © 2011-2022 走看看