UVa 1642 (综合) Magical GCD

题意:

给出一个数列,求一个连续的子序列,使得MGCD(i, j) =  该子序列的长度(j-i+1) × 子序列的gcd 最大,并输出这个最大值。

分析:

感觉可能要用优先队列,但貌似也用不上。

但类似地,从左往右枚举右端点,不难发现随着序列长度的增大,其子序列的最大公约数是非递增的。一般情况下,是呈阶梯状递减的。于是我们只要保留相同的gcd中,左端点最小的那个序列(因为相同的gcd里面它的长度最大,MGCD就是最大的)。

右端点更新的时候,同时也要更新每个子序列的gcd,然后把重复的gcd的子序列去掉,只保留长度最大的那个。

这样就减少了很多重复的gcd的计算。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5 typedef long long LL;
 6 
 7 const int maxn = 100000 + 10;
 8 LL a[maxn];
 9 
10 struct HEHE
11 {
12     LL g;   //gcd
13     int p;  //起始位置
14     HEHE(LL g=0, int p=0): g(g), p(p) {}
15     bool operator < (const HEHE& rhs) const
16     {
17         return g < rhs.g || (g == rhs.g && p < rhs.p);
18     }
19 };
20 
21 LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); }
22 
23 int main()
24 {
25     int T, n;
26     scanf("%d", &T);
27     while(T--)
28     {
29         scanf("%d", &n);
30         for(int i = 0; i < n; ++i) scanf("%lld", &a[i]);
31         LL ans = 0;
32         vector<HEHE> cur;
33         for(int j = 0; j < n; ++j)  //枚举右端点
34         {
35             cur.push_back(HEHE(0, j));
36             for(int k = 0; k < cur.size(); ++k) //更新gcd的值
37                 cur[k].g = gcd(cur[k].g, a[j]);
38             sort(cur.begin(), cur.end());
39 
40             vector<HEHE> nani;
41             for(int k = 0; k < cur.size(); ++k)
42                 if(k == 0 || cur[k-1].g != cur[k].g)
43                 {//相同的gcd每次只取最开头的数
44                     nani.push_back(cur[k]);
45                     ans = max(ans, cur[k].g * (j - cur[k].p + 1));
46                 }
47             cur = nani;
48         }
49 
50         printf("%lld\n", ans);
51     }
52 
53     return 0;
54 }
代码君

 

posted @ 2015-01-04 00:36  AOQNRMGYXLMV  阅读(344)  评论(0编辑  收藏  举报