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个数,哪些素因子被用过了,花费最少为多少。枚举一个数来转移即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int f[101][(1<<16)],a[101],n,tot,pri[18],inf,ans,zt[101]; 8 bool vis[61]; 9 int abs(int a) 10 { 11 if (a<0) return -a; 12 return a; 13 } 14 bool cmp(int a,int b) 15 { 16 return a>b; 17 } 18 int main() 19 { 20 int i,j,k,p,l,x,flag; 21 cin>>n; 22 for (i=1; i<=n; i++) 23 { 24 scanf("%d",&a[i]); 25 } 26 sort(a+1,a+n+1,cmp); 27 for (i=2; i<=60; i++) 28 if (vis[i]==0) 29 { 30 for (j=2*i; j<=60; j+=i) 31 vis[j]=1; 32 } 33 for (i=2; i<=58; i++) 34 if (vis[i]==0) 35 { 36 tot++; 37 pri[tot]=i; 38 } 39 for (i=2;i<=60;i++) 40 { 41 zt[i]=0; 42 for (j=1;j<=tot;j++) 43 if (i%pri[j]==0) 44 { 45 zt[i]|=(1<<j-1); 46 } 47 } 48 memset(f,127/3,sizeof(f)); 49 inf=f[0][0]; 50 f[0][0]=0; 51 for (i=1; i<=min(n,16); i++) 52 { 53 for (j=0; j<=(1<<16)-1; j++) 54 if(f[i-1][j]!=inf) 55 { 56 f[i][j]=min(f[i][j],f[i-1][j]+abs(a[i]-1)); 57 for (k=2;k<=60;k++) 58 if ((j&zt[k])==0) 59 { 60 f[i][j|zt[k]]=min(f[i][j|zt[k]],f[i-1][j]+abs(a[i]-k)); 61 } 62 63 } 64 } 65 ans=inf; 66 for (i=0; i<=(1<<16)-1; i++) 67 ans=min(ans,f[min(n,16)][i]); 68 for (i=min(n,16)+1;i<=n;i++) 69 ans+=abs(a[i]-1); 70 cout<<ans; 71 }