[CF453B] Little Pony and Harmony Chest

[CF453B] Little Pony and Harmony Chest - 状压dp,数论

Description

对于一个正整数序列 (b_i),当且仅当它的任意两个元素都互质时,这个序列 (b_i) 才是和谐的。宝箱的钥匙是能让以下表达式的值最小的和谐序列 (b_i)(sum_{i=1}^n|a_i-b_i|)。得到了序列 (a_i),求 (b_i)(n le 100, a_i le 30)

Solution

所有数的大小一定不超过 58,并且质因子的大小不超过 53

这样质数只有 16 个,考虑状压

(f[i][S]) 表示处理到第 i 位,当前用过的质因子集合 S,最小答案是多少

转移时枚举下一位填什么数,然后检查它的所有质因子是否 OK,每个数的质因子可以预处理并压成二进制,检查时候直接和 S 按位与就可以了,这样整个 dp 过程的复杂度为 (O(n m 2^{16}))

#include <bits/stdc++.h>
using namespace std;

#define int long long

signed main()
{
    ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vector<int> a(n + 2);
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    vector<vector<int>> f(n + 2, vector<int>(65536, 1e18));
    vector<vector<int>> from(n + 2, vector<int>(65536, 0));
    f[0][0] = 0;

    vector<int> primes;
    for (int i = 2; i <= 53; i++)
    {
        int flag = 1;
        for (int j = 2; j * j <= i; j++)
            if (i % j == 0)
                flag = 0;
        if (flag)
            primes.push_back(i);
    }

    vector<int> masks(66);
    for (int i = 1; i <= 58; i++)
    {
        int mask = 0;
        for (int j = 0; j < primes.size(); j++)
            if (i % primes[j] == 0)
                mask |= 1 << j;
        masks[i] = mask;
    }

    for (int i = 1; i <= n; i++)
    {
        vector<int> g(65536, 1e18);
        for (int j = 1; j <= 58; j++)
        {
            for (int s = 0; s < 65536; s++)
            {
                if (s & masks[j])
                    continue;
                int t = s | masks[j];
                f[i][t] = min(f[i][t], f[i - 1][s] + abs(a[i] - j));
                if (f[i][t] == f[i - 1][s] + abs(a[i] - j))
                {
                    from[i][t] = j;
                }
            }
        }
    }

    vector<int> ans(n + 2);
    int p = min_element(f[n].begin(), f[n].end()) - f[n].begin();

    for (int i = n; i >= 1; i--)
    {
        ans[i] = from[i][p];
        p &= ~masks[ans[i]];
    }

    for (int i = 1; i <= n; i++)
    {
        cout << ans[i] << " ";
    }
    cout << endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14467372.html