bzoj3136: [Baltic2013]brunhilda

这个题为什么会放在数据结构啊

首先因为有决策包容性,对于一个n每次必然选择一个n%p最大的p,令n减n%p

设fi表示i变成0的步数的话,同样我们可以知道f是有单调性的

假如fd能转移到fk,首先d一定是某个p的倍数,并且k-d+1<pi才能够转移

对于一个合法的d,它能够影响的长度就是pp,其中pp|d并且在给出的质数中是最大的,设它为s(d)

由于f有单调性,并且决策点影响的是由它开始往后的一段,那么决策也有单调性,假如我们知道了这个就可以O(n)指针扫决策点更新了

考虑如何求s

我们可以线性筛一次数,并把每个数被那个点标记记录下来,记为gi

先把每个给出的质数标记为自己,那么s(i)=max(s(i/gi),s(gi)) 好妙啊!

 

gb卡我空间

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std; 
const int maxn=1e5+100;
const int maxp=1e7+100;

int n,p[maxn];            int m,q[maxn];
int f[maxp],s[maxp];

int pr,g[maxp];bool v[maxp];
void dddd(int mx)
{
    for(int i=2;i<=mx;i++)
    {
        if(v[i]==false)
        {
            f[++pr]=i;
            g[i]=i;
        }
        for(int j=1;j<=pr&&i*f[j]<=mx;j++)
        {
            v[i*f[j]]=true;
            g[i*f[j]]=f[j];
            if(i%f[j]==0)break;
        }
    }
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]),s[0]=max(s[0],p[i]);
    int mx=0;
    for(int i=1;i<=m;i++)
        scanf("%d",&q[i]),mx=max(mx,q[i]);
    
    //.....read......
        
    dddd(mx);
    s[1]=-1;
    for(int i=1;i<=n;i++)s[p[i]]=p[i];
    for(int i=2;i<=mx;i++)s[i]=max(s[i/g[i]],s[g[i]]);
    
    //.....gets......
    
    f[0]=0;int j=0;
    for(int i=1;i<=mx;i++)
    {
        while(j<i&&(s[j]==-1||f[j]==-1||j+s[j]-1<i))j++;
        if(j==i)f[i]=-1;
        else f[i]=f[j]+1;
    }
        
    //.....getf.....
    
    for(int i=1;i<=m;i++)
    {
        if(f[q[i]]==-1)puts("oo");
        else printf("%d\n",f[q[i]]);
    }
    
    //.....print.....
    
    return 0;
}

 

posted @ 2019-01-24 11:37  AKCqhzdy  阅读(267)  评论(0编辑  收藏  举报