Codeforces Round #365 (Div. 2) E - Mishka and Divisors(转化成01-背包)

 

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

题意:

给出n个数和一个k,计算出至少要多少个数相乘才是k的倍数。

 

思路:
这道题目参考了杭电大神的代码http://blog.csdn.net/snowy_smile/article/details/52134304

对于每个数字,我们要么选,要么不选,这就很像01背包。但是肯定是需要预处理的。

对于每个数字,它所贡献的数就是它和k的最大公因数,这个不难理解吧。

所以我们可以把k的所有因子计算出来,因为有些因子很大,所以这里离散化一下,用map映射,这样后面才开得了数组。

我们用f[i][j]表示前i个数字,它们的gcd乘=映射j状态时的最佳方案。

当我们分析到第i个数字时,它所能贡献的数就是gcd(a[i],v[j]),那么它的前缀就是v[j]/gcd(a[i],v[j]),具体参见代码。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<string>
  6 #include<vector>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 using namespace std;
 11 typedef long long LL;
 12 const int maxn=1000+5;
 13 
 14 int n;
 15 LL k;
 16 LL s;
 17 LL a[maxn];
 18 LL b[maxn];
 19 pair<int,LL> f[maxn][maxn*10];
 20 vector<LL> v;
 21 map<LL,LL> key;
 22 
 23 LL gcd(LL a,LL b)
 24 {
 25     if(a<b)  swap(a,b);
 26     while(b!=0)
 27     {
 28         LL t=a;
 29         a=b;
 30         b=t%b;
 31     }
 32     return a;
 33 }
 34 
 35 void dp()
 36 {
 37     if(k==1)
 38     {
 39         puts("1");
 40         LL tmp =0x3f3f3f3f3f3f3f3f, ans=-1;
 41         for (int i = 1; i<=n;++i)
 42             if (a[i]<=tmp)
 43             {
 44                 ans=i;
 45                 tmp=a[i];
 46             }
 47         printf("%lld\n", ans);
 48         return;
 49     }
 50     for(int j=1;j<s;j++)   f[0][j]=make_pair(n+1,0);
 51     for(int i=1;i<=n;i++)
 52     {
 53         for (int j = 0; j < s; ++j)
 54         {
 55             f[i][j] = f[i - 1][j];
 56             int pre = key[v[j] / gcd(v[j], b[i])];
 57             f[i][j]=min(f[i][j], make_pair(f[i - 1][pre].first + 1, f[i - 1][pre].second + a[i]));
 58         }
 59     }
 60     if (f[n][s-1].first > n) puts("-1");
 61     else
 62     {
 63         printf("%d\n", f[n][s-1].first);
 64         for (int i = n; i; --i)
 65         {
 66             if (f[i][key[k]] != f[i - 1][key[k]])
 67             {
 68                 printf("%d ", i);
 69                 k /= gcd(k, b[i]);
 70             }
 71         }
 72         puts("");
 73     }
 74 }
 75 
 76 int main()
 77 {
 78     //freopen("D:\\input.txt","r",stdin);
 79     while(~scanf("%d%lld",&n,&k))
 80     {
 81         LL m=sqrt(k+0.5);
 82         v.clear();
 83         for(int i=1;i<=m;i++)
 84         {
 85             if(k%i==0)
 86             {
 87                 v.push_back(i);
 88                 if(k/i!=i)  v.push_back(k/i);
 89             }
 90         }
 91         sort(v.begin(),v.end());
 92         s=v.size();
 93         key.clear();
 94         for(int i=0;i<s;i++)  key[v[i]]=i;
 95         for(int i=1;i<=n;i++)
 96         {
 97             scanf("%lld",&a[i]);
 98             b[i]=gcd(k,a[i]);
 99         }
100         dp();
101     }
102     return 0;
103 }

 

posted @ 2017-05-17 21:47  Kayden_Cheung  阅读(265)  评论(0编辑  收藏  举报
//目录