• Codeforces Round #365 (Div. 2) E


    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
    ", 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
    ", 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 }
  • 相关阅读:
    总结ORACLE学习8023
    set @CurrentID=@@IDENTITY
    一个IT人:跳槽一定要谨慎
    SQL Server数据库开发(转自CSDN)
    46个不得不知的生活小常识
    CodeProjectSome Cool Tips For .Net 之一
    数据库原理综合习题答案
    EDM
    CodeProject Some Cool Tips for .NET之二
    The operation is not valid for the state of the transaction.
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/6869705.html
Copyright © 2020-2023  润新知