首先每次都去掉尽量多的人,可以证明这样贪心是最优的
然后递推,f[i]表示i最少操作多少次到0,j表示当前离i最远的i-i%p[x]的点,f[i]=f[j]+1,如果j不满足条件了就要向后找j
因为f[i]是单调不降的,所以我们需要找最小的j使得j能对i产生贡献
j能对当前的i产生贡献,易知j一定是题目给定某一个的质数p[x]的倍数,需要知道j的质因子里面含题目给定的质数的最大的那个,预处理出每个数最小的质因数minp,对于i含的最大的p[x]的只要看minp和i/minp
时间复杂度O(n)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 10001000;
const int maxm = 101000;
int minp[maxn],pr[maxn/10],pri;
int v[maxn];
int pi[maxm],p[maxm],f[maxn],n,m,up;
int q[maxm];
void pre()
{
pri=0; minp[1]=1;
for(int i=2;i<up;i++)
{
if(!v[i])
{
pr[++pri]=i;
minp[i]=i;
}
for(int j=1;j<=pri;j++)
{
int k=pr[j]*i;
if(k>=up) break;
v[k]=1;
minp[k]=pr[j];
if(i%pr[j]==0) break;
}
}
}
int main()
{
up=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&pi[i]);
for(int i=1;i<=m;i++) scanf("%d",&q[i]),up=max(up,q[i]+1);
pre();
memset(v,0,sizeof v);
sort(pi+1,pi+n+1);
int nn=0;
for(int i=1;i<=n;i++)
if(pi[i]!=pi[i-1])
p[++nn]=pi[i],v[p[nn]]=p[nn];
n=nn;
v[0]=p[n];
f[0]=0;
int j=0;
for(int i=1;i<up;i++)
{
while(i-j>=v[j]||!v[j])
{
j++;
if(i==j) break;
}
if(i==j) {up=i; break;}
f[i]=f[j]+1;
v[i]=max(v[minp[i]],v[i/minp[i]]);
}
for(int i=1;i<=m;i++)
{
int x=q[i];
if(x>=up) printf("oo\n");
else printf("%d\n",f[x]);
}
return 0;
}