LGTB 与序列

时间:2023-03-09 19:29:28
LGTB 与序列

LGTB 有一个长度为N 的序列A,现在他想构造一个新的长度为N 的序列B,使得B 中的任意两个数都
互质。
并且他要使ai与bi对应项之差最小
请输出最小值
输入
第一行包含一个数N 代表序列初始长度
接下来一行包含N 个数A1, A2, …, AN,代表序列A
对于40% 的数据,1 N 10
对于100% 的数据,1 N 100, 1 ai 30
输出
输出包含一行,代表最小值
样例
样例输入样例输出
51
6 4 2 8
3
样例说明
样例中B 数组可以为1 5 3 1 8

考虑到bi最多变成58,如果变成更大的数还不如变成1,而且58之内只有16个素数
并且可以证明对于两个数a > b,变成的数A >= B
所以最多只有16个最大的数变成素数,其他的数都会变成1

所以直接对于前16个数dp,dp[i][j]代表到第i个数,哪些素因子被用过了,花费最少为多少。枚举一个数来转移即可

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int f[][(<<)],a[],n,tot,pri[],inf,ans,zt[];
bool vis[];
int abs(int a)
{
if (a<) return -a;
return a;
}
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
int i,j,k,p,l,x,flag;
cin>>n;
for (i=; i<=n; i++)
{
scanf("%d",&a[i]);
}
sort(a+,a+n+,cmp);
for (i=; i<=; i++)
if (vis[i]==)
{
for (j=*i; j<=; j+=i)
vis[j]=;
}
for (i=; i<=; i++)
if (vis[i]==)
{
tot++;
pri[tot]=i;
}
for (i=;i<=;i++)
{
zt[i]=;
for (j=;j<=tot;j++)
if (i%pri[j]==)
{
zt[i]|=(<<j-);
}
}
memset(f,/,sizeof(f));
inf=f[][];
f[][]=;
for (i=; i<=min(n,); i++)
{
for (j=; j<=(<<)-; j++)
if(f[i-][j]!=inf)
{
f[i][j]=min(f[i][j],f[i-][j]+abs(a[i]-));
for (k=;k<=;k++)
if ((j&zt[k])==)
{
f[i][j|zt[k]]=min(f[i][j|zt[k]],f[i-][j]+abs(a[i]-k));
} }
}
ans=inf;
for (i=; i<=(<<)-; i++)
ans=min(ans,f[min(n,)][i]);
for (i=min(n,)+;i<=n;i++)
ans+=abs(a[i]-);
cout<<ans;
}