题意:n个数a[i],找到一组序列B,B中任意两个元素互质,最小值为? n<=100,a[i]<=30
一定有解 并且b[i]不超过2*a[i]-1 若超过,b[i]用1来代替显然更优
b[i]范围被限制在60内,又要满足两两互质,用二进制记录前i个数中素因子出现的状态
设dp[i][s] 前i个数 素因子出现状态为s 则新添加的x要满足num[x]&s==0 否则有大于1的公约数 num[i]为i包含素因子的二进制状态
pre保存当前决策 复杂度为O(n*2^16*60)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e2+20;
const int M=1<<17;
const int inf=0x3f;
int a[N],b[N],n,pri[N],pn,num[N];//num[i] i°üº¬ËØÒò×ӵĶþ½øÖÆ״̬
int pre[N][M],dp[N][M];
void init()
{
memset(num,0,sizeof(num));
pn=0;
int vis[110]={0};
for(int i=2;i<60;i++)
{
if(vis[i]==0)
{
pri[pn++]=i;
for(int j=i+i;j<60;j+=i)
vis[j]=1;
}
}
for(int i=2;i<60;i++)
{
for(int j=0;j<pn;j++)
{
if(i%pri[j]==0)
num[i]|=1<<j;
}
}
}
int main()
{
init();
while(cin>>n)
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int s=0;s<M;s++)
{
for(int x=1;x<60;x++)
{
//Ç°Ò»¸ö״̬ҪºÏ·¨
if(dp[i-1][s]==inf||(num[x]&s))
continue;
int res=dp[i-1][s]+abs(x-a[i]);
if(dp[i][s|num[x]]>res)
{
dp[i][s|num[x]]=res;
pre[i][s|num[x]]=x;
}
}
}
}
int pos,ans=2e8;
for(int s=0;s<M;s++)
{
if(ans>dp[n][s])
ans=dp[n][s],pos=s;
}
for(int i=n;i>=1;i--)
{
b[i]=pre[i][pos];
pos=pos^num[b[i]];
}
for(int i=1;i<=n;i++)
printf("%d%c",b[i],i==n?'\n':' ');
}
return 0;
}