• [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;
    }
    
  • 相关阅读:
    触发器
    数据库一键退出脚本
    集合
    Android 自定义控件之继承ViewGroup创建新容器
    web学习测试环境
    ref:ubuntu下如何批量修改文件后缀名
    ref:Adding AFL Bloom Filter to Domato for Fun
    ref:phpstorm配置远程调试(xdebug)(docker中)
    ref:PHP反序列化漏洞成因及漏洞挖掘技巧与案例
    ref:【干货分享】PHP漏洞挖掘——进阶篇
  • 原文地址:https://www.cnblogs.com/mollnn/p/14467372.html
Copyright © 2020-2023  润新知