题意:给你一个a数组,让你构造一个b数组,使得b数组之间的数互质,且和a数组之间的差的和最小。
因为a最大是30,而b={1,1,...1}是一组解,所以b最大可取2*30-1 = 59,因为超过59还不如选1. 所以我们可以先对1-59质因数分解。然后用状态压缩dp做。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
//#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
#define maxn 105
#define mod 1000000009
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int fac[65];// fac[i]表示的是当前数包含哪些素因子
int prime[17] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59 }; //小于60的素数
int dp[maxn][1<<17]; //dp[i][j]表示的是前i个数在状态为j的情况下的最小差
int path[maxn][1<<17]; //path[i][j]表示的是使dp[i][j]最小第i个(即当前最后一个)放的是什么
int a[maxn],b[maxn];
int n;
void init()
{
ini(fac);
for(int k = 1;k < 60; k++)
{
rep(i,17)
if(k % prime[i] == 0) fac[k] |= 1<<i;
}
}
void solve()
{
rep(i,n) rep(j,1<<17) dp[i][j] = INF;
//下面介绍一种状态压缩的优化版本,当然这题不优化也能过
rep(i,n)
{
for(int k = 1;k < 60; k++)
{
int x = (~fac[k]) & ((1<<17) - 1); //这一步比较高端,x表示的是当前为k的倩况下前一个合法状态的集合
for(int s = x; ;s = (s - 1) & x) //这循环也很高端,他把那些为1的位枚举了一遍,为0的位一直为0,这样可以减少循环次数
{
if(dp[i][s | fac[k]] > dp[i-1][s] + abs(a[i] - k))
{
dp[i][s | fac[k]] = dp[i-1][s] + abs(a[i] - k);
path[i][s | fac[k]] = k;
}
if(s == 0) break;
}
}
}
int mn = INF,x;
rep(i,1<<17)
{
if(mn > dp[n-1][i])
{
mn = dp[n-1][i];
x = i; //x表示的是取最小的状态
}
}
for(int i = n-1;i >= 0; i--)
{
b[i] = path[i][x];
x ^= fac[b[i]];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
init();
while(~scanf("%d",&n))
{
rep(i,n) scan(a[i]);
solve();
rep(i,n)
{
printf("%d%c",b[i],i==n-1?'\n':' ');
}
}
return 0;
}