cf/codeforces #365 E - Mishka and Divisors 数学+背包dp+gcd

原创 2016年08月31日 13:58:41

Problem E - Mishka and Divisors

题目大意

 给n,k,给n个数,让你挑出m个数,使得m个数的乘积是k的倍数,输出最小的m。

如果有多个方案,输出sum最小的方案,(方案输出所选数的下标)

   数据范围:n <= 1000, k <= 10^12, ai<=10^12。


解题分析

  dp[i][j]表示前i个数里选一些数,使得乘积是j的倍数的最小的m。

sum[i][j]表示最优方案对应的sum

可以得知,dp[i][j]=min(dp[i-1][j],dp[i-1] [ j/gcd(j,a[i])]    )

也就是要么不选a[i],如果选a[i]就在前面选前i-1个数取到j/gcd(j,a[i])的方案

记得相应的sum值也要更新。

        

这里的i就是1到n,而j应该是 k的约数们,可以知道k的约数个数大概是lg至上,sqrt未满的一个数量级, 

粗略估计一下不超过1W ?  不过最后内存用了17X mb ...还好是cf

把k的约数们用map映射一下就好了

时间卡得紧,会T,注意到 求gcd(j,a[i])的时候,可以先令b[i]=gcd(k,a[i]),最后直接求gcd(j,b[i])能省一些时间



参考程序


 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 1005;

ll aa[N];
ll bb[N];
ll prim[11000+50];
ll ok=0;
void f(ll k)
{
    for (ll i=1; i*i<=k; i++)
        if (k%i==0)
        {
            prim[++ok]=i;
            if (k/i!=i)
                prim[++ok]=k/i;
        }
}
ll dp[N][11000+50];
ll sum[N][11000+5];
map <ll,int>idx;
ll gcd(ll a,ll b)
{
    if (!b) return a;
    else return gcd(b,a%b);
}
int main()
{
    ll n,k;
    cin>>n>>k;
    ll tmp=k;
    for (int i=1; i<=n; i++)
    {
        scanf("%lld",&aa[i]);
        bb[i]=gcd(k,aa[i]);
    }
    if (k==1)
    {
        printf("1\n");
        printf("%d\n",(min_element(aa+1,aa+1+n)-aa));
        return 0;
    }
    f(k);
    sort(prim+1,prim+1+ok);
    for (int i=1; i<=ok; i++)
        idx[prim[i]]=i;
     for (int j=2; j<=ok; j++)
    {
        if (aa[1]%prim[j]==0)
            dp[1][j]=1,sum[1][j]=aa[1];
        else dp[1][j]=n+1;
    }
    dp[1][1]=0;
    for (int i=2; i<=n; i++)
    {
        for (int j=1; j<=ok; j++)
        {
            dp[i][j]=dp[i-1][j];
            sum[i][j]=sum[i-1][j];
            ll v=prim[j]/gcd(prim[j],bb[i]);
            int id=idx[v];
            if (dp[i-1][id]+1 < dp[i][j]  )
            {
                dp[i][j]=dp[i-1][id]+1;
                sum[i][j]=sum[i-1][id]+aa[i];
            }
            else if (dp[i-1][id]+1==dp[i][j])
            {
                if (sum[i][j]>sum[i-1][id]+aa[i])
                    sum[i][j]=sum[i-1][id]+aa[i];
            }
        }
    }
    if (dp[n][ok]>n)
    {
        printf("-1\n");
        return 0;
    }
    printf("%lld\n",dp[n][ok]);
    tmp=k;
    for (int i=n; i>=1; i--)
    {
        int id=idx[tmp];
        if (dp[i][id]==dp[i-1][id]&& sum[i][id]==sum[i-1][id]) continue;
        printf("%d ",i);
        tmp/=gcd(tmp,bb[i]);
    }
    printf("\n");



    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【DP算法篇之初学】背包问题

昨天做了爱奇艺的内推笔试,编程题又出现了动态规划问题,感觉动态规划出现的概率好大,需要加强下。这里借用背包问题开始我们的学习。 背包问题的经典讲解可以参见背包问题九讲,此外我在刷题的过程中发现还发...
  • woxiaohahaa
  • woxiaohahaa
  • 2016年08月31日 10:13
  • 3551

DP背包问题小结(01背包,完全背包,需恰好装满或不需,一维DP、二维DP)

1) 01背包基础,求背包所装物品价值之和的最大值,不要求恰好装满时,采用易于理解的二维DP数组存储。 #include #include using namespace std; int d...
  • a272846945
  • a272846945
  • 2016年03月17日 22:53
  • 2109

【打CF,学算法——二星级】CodeForces 689A Mike and Cellphone (模拟)

题目链接:CF 689A 题面: A. Mike and Cellphone time limit per test 1 second memory limit per test 256...
  • David_Jett
  • David_Jett
  • 2016年07月08日 10:18
  • 1175

CF#365-D. Mishka and Interesting sum-树状数组/线段树离线处理区间查询

http://codeforces.com/contest/703/problem/D 题意:求一组数的任意区间[L,R]内的  出现偶数次的异或和,如果 是奇数次,那直接就是前缀和咯。现在是偶数...
  • viphong
  • viphong
  • 2016年08月07日 21:36
  • 285

Codeforces Round #365 (Div. 2) A(暴力) B(数学技巧) C(二分)D(线段树+离散)E(乘除法DP+约数分解+map映射)

传送门:A. Mishka and Game 暴力记录两人赢的次数,最后将次数再比较一次即可 #include using namespace std; int n; int main()...
  • guhaiteng
  • guhaiteng
  • 2016年08月06日 13:23
  • 506

【Codeforces Round 365 (Div 2)A】【水题】Mishka and Game

A. Mishka and Game time limit per test 1 second memory limit per test 256 megabytes ...
  • snowy_smile
  • snowy_smile
  • 2016年08月06日 09:07
  • 256

【Codeforces Round 365 (Div 2)B】【容斥】Mishka and trip 环加完全点图的边权乘积和

B. Mishka and trip time limit per test 1 second memory limit per test 256 megabytes ...
  • snowy_smile
  • snowy_smile
  • 2016年08月06日 09:08
  • 370

Codeforces Round #365 (Div. 2) 703B Mishka and trip 水题

Mishka and trip time limit per test 1 second memory limit per test 256 megabytes in...
  • kyoma
  • kyoma
  • 2016年08月05日 12:59
  • 284

Codeforces 365(Div.2)A.Mishka and Game【水题】

A. Mishka and Game time limit per test 1 second memory limit per test 256 megabytes ...
  • mengxiang000000
  • mengxiang000000
  • 2016年08月05日 08:35
  • 207

Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum(树状数组)

D. Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megabyte...
  • liangzhaoyang1
  • liangzhaoyang1
  • 2016年08月10日 09:39
  • 373
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:cf/codeforces #365 E - Mishka and Divisors 数学+背包dp+gcd
举报原因:
原因补充:

(最多只允许输入30个字)