Codeforces Round #259 (Div. 1)——Little Pony and Harmony Chest

题目连接

  • 题意:
    给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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值