LGTB 与 序列

题目描述

LGTB 有一个长度为 N 的序列 A ,现在他想构造一个新的长度为 N 的序列 B ,使得 B 中的任意两个数都互质。并且他要使

\sum_{1\le i\le N}|A_i-B_i|

最小,请输出最小值。

输入格式

  • 第一行包含一个数 N 代表序列初始长度。
  • 接下来一行包含 N 个数 A_1, A_2, …, A_N ,代表序列 A

输出格式

输出包含一行,代表最小值。

样例

样例输入

5
1 6 4 2 8

样例输出

3

数据范围与提示

  • 样例解释: B=\{1,5,3,2,7\} 1 与任何数都互质。
  • 对于 40\% 的数据, 1 ≤ N ≤ 10
  • 对于 100\% 的数据, 1 ≤ N ≤ 100, 1 ≤ A_i≤30

code

/*
5
1 6 4 2 8
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
const int Inf = 0x3f3f3f3f;
int prime[] = { 0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 };
bool cmp(int a, int b) { return a > b; }

int a[maxn], dp[17][1 << 17];
int jl[maxn];

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + n + 1, cmp);
    memset(jl, 0, sizeof(jl));
    for (int i = 1; i <= 58; i++)
        for (int j = 1; j <= 16; j++)
            if (i < prime[j])
                break;
            else if (i % prime[j] == 0)
                jl[i] |= (1 << j - 1);

    memset(dp, 0x3f, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1; i <= min(n, 16); i++)
        for (int j = 0; j < (1 << 16); j++)
            for (int num = 1; num <= 58; num++)
                if (!(jl[num] & j)) {
                    int s = j | jl[num];
                    dp[i][s] = min(dp[i][s], dp[i - 1][j] + abs(a[i] - num));
                }
    int ans = Inf;
    for (int j = 0; j < (1 << 16); j++) ans = min(ans, dp[min(n, 16)][j]);
    if (n > 16)
        for (int i = 17; i <= n; i++) ans += abs(a[i] - 1);
    return cout << ans, 0;
}
posted @ 2020-07-08 20:22  hyskr  阅读(290)  评论(0编辑  收藏  举报