BZOJ3136: [Baltic2013]brunhilda

来源:互联网 发布:淘宝旺旺设置自动回复 编辑:程序博客网 时间:2024/05/17 08:26

首先每次都去掉尽量多的人,可以证明这样贪心是最优的
然后递推,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 longusing 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;}
0 0
原创粉丝点击