您的位置:首页 > 其它

[BZOJ 2790]POI2012 Distance

2014-12-16 16:49 330 查看
乍一看以为是神题,想了想,原来很暴力。。。

可以看到乘和除是没有顺序关系的,那么为了我们就统一先除再乘。

假设我们已经把原数除完了变成x,那么再在x上乘一些数使得得到的数在所有书中所需的步数最小,记为min1,次小的几为min2。

预处理大法~~~~

对每个数字枚举所有约数d,更新的最小值。

在计算答案,同样枚举约数,利用min1或min2计算即可。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int INF=1e9;
int check[1000005],prime[1000000],cnt,ans,i,j,tot,x,n,minx;
int p[100005][10],k[100005][10],s[100005],t[100005];
int min1[1000005],min2[1000005],num1[1000005],num2[1000005];

void init(){
for (i=2;i<=1000000;i++){
if (check[i]==0) check[i]=i, prime[++tot]=i;
for (j=1;j<=tot;j++){
if (i*prime[j]>1000000) break;
check[i*prime[j]]=prime[j];
if (i%prime[j]==0) break;
}
}
}

void dfs(int x,int dig,int cnt){
if (x>t[i]){
if (min1[dig]>cnt){
min2[dig]=min1[dig]; num2[dig]=num1[dig];
min1[dig]=cnt; num1[dig]=i;
} else
if (min2[dig]>cnt){
min2[dig]=cnt;
num2[dig]=i;
}
return;
}
for (int j=0;j<=k[i][x];j++){
dfs(x+1,dig,cnt-j);
dig=dig*p[i][x];
}

}

void work(int x,int dig,int cnt){
if (x>t[i]){
if (i==num1[dig]){
if (min2[dig]+cnt<minx || (min2[dig]+cnt==minx &&  ans>num2[dig])){
ans=num2[dig];
minx=min2[dig]+cnt;
}
} else
{
if (min1[dig]+cnt<minx || (min1[dig]+cnt==minx &&  ans>num1[dig])){
ans=num1[dig];
minx=min1[dig]+cnt;
}
}
return;
}
for (int j=0;j<=k[i][x];j++){
work(x+1,dig,cnt-j);
dig=dig*p[i][x];
}

}

int main(){
//freopen("odl.in","r",stdin);
//freopen("odl.out","w",stdout);
init();
scanf("%d",&n);
memset(min1,127/2,sizeof(min1));
memset(min2,127/2,sizeof(min2));
for (i=1;i<=n;i++){
scanf("%d",&x);
s[i]=0; t[i]=0;
while (x>1){
p[i][ ++t[i] ] = check[x];
k[i][ t[i] ] = 0;
while (x%p[i][t[i]]==0)
x/=p[i][t[i]], k[i][ t[i] ]++, s[i]++;
}
dfs(1,1,s[i]);
}
for (i=1;i<=n;i++){
minx=INF; ans=INF;
work(1,1,s[i]);
//printf("%d %d\n",minx,ans);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: