Description
给定m
个素数和Q
个询问。每个询问有n
个人,每次操作可以任意选择其中的一个素数p
(素数可以重复使用),然后去掉剩余人数 mod p
个人。对于每个询问,我们想知道,至少需要多少步操作才能去掉所有人。
Input
第一行:素数个数m
和询问个数Q
(1 <= m <= 100 000
, 1 <= 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; }