• Mishka and Divisors[CodeForces Round #365 Div.2]


    http://codeforces.com/contest/703/problem/E

    题意:给定一个最多个数的序列,从中选出最少个数的数字,使得他们的乘积是k的倍数,若有多种选择方式,输出选出数字和最小的一种,若有多种,输出任意一种。

    动态规划,dp[i][j]表示从前i个数里选,所得乘积是j的倍数。显然dp[i][j]=max(dp[i-1][j],dp[i-1][j/gcd(j,a[i])])。由于k可能很大,所以只需令j分别等于k的每个约数即可。

    确定k的约数的时候令i从1到sqrt(k)循环判断,注意由于k很大,这里的i要使用longlong。

    #include<bits/stdc++.h>
    using namespace std;
    #define ft first
    #define sd second
    #define mp make_pair
    long long a[1100], k, f[11000], b[1100];
    int fc, n;
    pair<int, long long> dp[1100][11000];
    map<long long , int> e;
    int main()
    {
        //freopen("input.txt", "r", stdin);
        scanf("%d%I64d", &n, &k);
        long long t = k;
        for (int i = 1; i <= n; i++)
        {
            scanf("%I64d", &a[i]);
            b[i] = __gcd(k, a[i]);
            t /= __gcd(t, a[i]);
        }
        if (t != 1)
        {
            printf("-1
    ");
            return 0;
        }
        if (k == 1)
        {
            printf("1
    %d
    ", (int)(min_element(a + 1, a + n + 1) - a));
            return 0;
        }
        e.clear();
        fc = 0;
        for (long long i = 1; i * i <= k; i++)
        {
            if (k % i != 0) continue;
            f[fc++] = i;
            if (i * i != k) f[fc++] = k / i;
        }
        sort(f, f + fc);
        for (int i = 0; i < fc; i++)
            e[f[i]] = i;
        for (int i = 1; i < fc; i++)
            dp[0][i] = mp(n + 1, 0);
        dp[0][0] = mp(0, 0);
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < fc; j++)
            {
                dp[i][j] = dp[i - 1][j];
                long long v = e[f[j] / __gcd(f[j], b[i])];
                if (dp[i][j] > mp(dp[i - 1][v].ft + 1, dp[i - 1][v].sd + a[i]))
                    dp[i][j] = mp(dp[i - 1][v].ft + 1, dp[i - 1][v].sd + a[i]);
            }
        printf("%d
    ", dp[n][fc - 1].ft);
        t = k;
        for (int i = n; i > 0; i--)
        {
            if (dp[i][e[t]] == dp[i - 1][e[t]]) continue;
            printf("%d ", i);
            t /= __gcd(t, b[i]);
        }
        printf("
    ");
        //fclose(stdin);
        return 0;
    }
    View Code
  • 相关阅读:
    1-29反射
    1-28Map简介
    1-27TreeSet简介
    1-26HashSet简介
    1-25泛型
    1-24List三个子类的特点
    1-23集合概述
    Java接口
    1-22日期类型
    简易计算器的实现
  • 原文地址:https://www.cnblogs.com/dramstadt/p/5759206.html
Copyright © 2020-2023  润新知