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 }