BZOJ1130: [POI2008]POD Subdivision of Kingdom 状压+dfs+恶心题
BZOJ2794: [Poi2012]Cloakroom 离线+背包

BZOJ2790: [Poi2012]Distance 数学+线性筛

shinbokuow posted @ Sep 15, 2015 07:19:14 PM in BZOJ with tags 数学 线性筛 , 1289 阅读

 

题解:

令$num[i]$表示将$i$分解质因数之后所有质因子幂次的和。

则不难发现:$d(x,y)=num[\frac{x}{gcd(x,y)}]+num[\frac{y}{gcd(x,y)}]=num[x]+num[y]-2num[gcd(x,y)]$。

证明可以考虑将每个质因子分开考虑得到。

因此,我们对于每一个$a[i]$,枚举$a[i]$的所有因数$b$,并用所有是$b$的倍数的$a[j]$更新答案。

有人会问如果$b$并不是$gcd(a[i],a[j])$怎么办,这种情况一定不会有枚举到$b=gcd(a[i],a[j])$的时候优,所以枚举进去并不成问题。

我们需要对于每个$b$预处理所有是$b$的倍数的$a[i]$的$num$最小值,若有多个则取标号的最小值,由于$a[i]$自己可能作为答案所以要维护最小和次小。

令$N=10^6$。

这可以暴力做到$O(NlnN)$。

然后进行刚才的计算,时间复杂度为$O(n\sqrt{N})$。

这里涉及到求$num$以及线性求所有约数,都可以利用线性筛处理,详情见代码。

于是就做完了。

代码:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
inline int getc(){
    static const int L=1<<15;
    static char buf[L],*S=buf,*T=buf;
    if(S==T){
        T=(S=buf)+fread(buf,1,L,stdin);
        if(S==T)
            return EOF;
    }
    return*S++;
}
 
inline int getint(){
    int c;
    while(!isdigit(c=getc()));
    int x=c-'0';
    while(isdigit(c=getc()))
        x=(x<<1)+(x<<3)+c-'0';
    return x;
}
 
typedef pair<int,int> pii;
#define mp make_pair
 
#define N 1000010
int a[100010];
int p[N],lp[N],num[N],cnt;
bool np[N];
void pre(int n){
    int i,j;
    for(i=2;i<=n;++i){
        if(!np[i]){
            p[++cnt]=i;
            num[i]=1;
            lp[i]=i;
        }
        for(j=1;j<=cnt&&p[j]*i<=n;++j){
            np[i*p[j]]=1;
            num[i*p[j]]=num[i]+1;
            lp[i*p[j]]=p[j];
            if(i%p[j]==0)
                break;
        }
    }
}
 
int pri[110],ti[110],id;
void divide(int x){
    for(id=0;x!=1;x/=lp[x]){
        if(lp[x]==pri[id])
            ++ti[id];
        else{
            pri[++id]=lp[x];
            ti[id]=1;
        }
    }
}
 
int sav[N],nums;
void dfs(int dep,int x){
    if(dep>id){
        sav[++nums]=x;
        return;
    }
    for(int i=0;i<=ti[dep];++i,x*=pri[dep])
        dfs(dep+1,x);
}
 
#define inf 0x3f3f3f3f
struct Ans{
    pii mn,_mn;
    Ans():mn(mp(inf,0)),_mn(mp(inf,0)){}
    void upd(int x,int y){
        if(mp(x,y)<mn){
            _mn=mn;
            mn=mp(x,y);
        }
        else if(mp(x,y)<_mn)
            _mn=mp(x,y);
    }
}f[N];
 
int ins[N][2];
 
int main(){
#ifndef ONLINE_JUDGE
    //freopen("tt.in","r",stdin);
#endif
    int n=getint(),i,j,k;
    for(i=1;i<=n;++i)
        a[i]=getint();
    for(i=1;i<=n;++i){
        if(!ins[a[i]][0])
            ins[a[i]][0]=i;
        else if(!ins[a[i]][1])
            ins[a[i]][1]=i;
    }
     
 
    pre(1000000);
     
    for(i=1;i<=1000000;++i)
        for(j=i;j<=1000000;j+=i){
            if(ins[j][0])
                f[i].upd(num[j],ins[j][0]);
            if(ins[j][1])
                f[i].upd(num[j],ins[j][1]);
        }
     
    for(i=1;i<=n;++i){
        divide(a[i]);
        nums=0;
        dfs(1,1);
        pii ans(inf,0);
        for(j=1;j<=nums;++j){
            if(f[sav[j]].mn.second==i)
                ans=min(ans,mp(num[a[i]]-2*num[sav[j]]+f[sav[j]]._mn.first,f[sav[j]]._mn.second));
            else
                ans=min(ans,mp(num[a[i]]-2*num[sav[j]]+f[sav[j]].mn.first,f[sav[j]].mn.second));
        }
        printf("%d\n",ans.second);
    }
     
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter