题目连接
- 题意:
给n个整数ai,求一个序列bi,使得b序列中任意两个数互质,而且sigma(abs(ai - bi))最小,输出任意一个b序列即可
(1 ≤ n ≤ 100) (1 ≤ ai ≤ 30)
- 分析:
首先明确一点,题目没有限制b的范围。。。。为此wa了好多次,不过可以推断出来,b肯定小于等于60
任意两个数互质,也就是说,对于新加入的一个bi,如果知道了之前所有数的质因子,那么当前数只要没有这个质因子就是一种满足的情况。而60以内的质数不到20个,所以直接状压DP即可。DP[i][j],表示处理到第i个数,所含的质因子为j(二进制形式)
const int MAXN = 60;
const int SIZE = 16;
int ipt[110];
int dp[110][1 << SIZE];
int p[110][1 << SIZE];
int x[110][1 << SIZE];
int to[MAXN + 1];
int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
map<int, int> mp;
void init()
{
REP(i, SIZE)
mp[prime[i]] = 1 << i;
FE(ii, 0, MAXN)
{
int n = ii, ret = 0, i;
for (i = 0; i < SIZE && prime[i] * prime[i] <= n; i++)
if (n % prime[i] == 0)
{
while (n % prime[i] == 0)
n /= prime[i];
ret += 1 << i;
}
if (n > 1)
ret += mp[n];
to[ii] = ret;
}
}
int n;
void dfs(int idx, int id)
{
if (idx >= 2)
dfs(idx - 1, p[idx][id]);
printf("%d%c", x[idx][id], idx == n ? '\n' : ' ');
}
int main ()
{
int all = 1 << SIZE;
init();
while (~RI(n))
{
FE(i, 1, n)
RI(ipt[i]);
CLR(dp, INF); dp[0][0] = 0;
FE(i, 0, n - 1)
{
FF(j, 0, all)
{
FE(jj, 0, MAXN)
{
int v = to[jj];
if (j & v)
continue;
int val = dp[i][j] + abs(jj - ipt[i + 1]);
int& nxt = dp[i + 1][j | v];
if (val < nxt)
{
nxt = val;
p[i + 1][j | v] = j;
x[i + 1][j | v] = jj;
}
}
}
}
int ans = INF, id = 0;
REP(j, all)
{
if (dp[n][j] < ans)
{
ans = dp[n][j];
id = j;
}
}
dfs(n, id);
}
return 0;
}