ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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\n",f[qs[i]]);
        else puts("oo");
    }
    return 0;
}

 

posted on 2016-11-15 20:11  nul  阅读(446)  评论(0编辑  收藏  举报