CGCDSSQ Codeforces 475D

思路:将数据存入gcd二维数组的第0列,第j列的gcd值是第j-1列的i行和i+2的j次方的最大公约数,

gcd[i][j] = Gcd(gcd[i][j - 1], gcd[i + bin[j - 1]][j - 1]);

将gcd数组计算好后,进行询问query,由于系统的Log2太慢,所以编写了Log数组直接使用。
int k = Log[r - l + 1];
return Gcd(gcd[l][k], gcd[r - bin[k] + 1][k]);
二分查找bi函数:将左端固定值为x,寻找值仍为x的右端,并返回;遍历完成即统计完成。
 1 #include<iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include<algorithm>
 5 #include<map>
 6 #define maxn 100010
 7 using namespace std;
 8 typedef long long LL;
 9 int gcd[maxn][32], n, Log[maxn], bin[32];
10 map<int, LL> mp;
11 int Gcd(int a, int b) {
12     return b ? Gcd(b, a % b) : a;
13 }
14 void rmqInit() {
15     Log[0] = -1; bin[0] = 1;
16     for (int i = 1; i < 20; ++i) {
17         bin[i] = bin[i - 1] << 1;//1 2 4 8 16 32
18     }
19     for (int i = 1; i <= n; ++i) {
20         Log[i] = Log[i >> 1] + 1;//-1 0 1 1 2 2 2 2 3 3 3 3 3 3 3 3 
21     }
22     for (int j = 1; bin[j] <= n; ++j) {
23         for (int i = 1; i + bin[j - 1] - 1 <= n; ++i) {
24             gcd[i][j] = Gcd(gcd[i][j - 1], gcd[i + bin[j - 1]][j - 1]);
25         }
26     }
27 }
28 int query(int l, int r) {//询问区间为l,r的gcd值
29     int k = Log[r - l + 1];//
30     return Gcd(gcd[l][k], gcd[r - bin[k] + 1][k]);//bin[k]就是2的k次方
31 }
32 int bi(int i, int l, int r, int x) {  //x是i到l的最大公约数
33     while (r - l > 1) {  //右区间-左区间等于1时停止
34         int mid = l + r >> 1;  
35         int val = query(i, mid);
36         if (val >= x) l = mid;   
37         else r = mid - 1; 
38     }
39     //找出最大公约数是x的右区间
40     return query(i, r) == x ? r : l;
41 }
42 int main() {
43     scanf_s("%d", &n);
44     for (int i = 1; i <= n; ++i) {
45         cin >> gcd[i][0];
46     }
47     rmqInit();
48     for (int i = 1; i <= n; ++i) {
49         int l = i;    //左区间从1到n,一行一行搜索
50         while (true) {
51             if (l == n + 1) break;  //左区间超过n则跳出
52             int val = query(i, l);   //询问区间为i,l的gcd值
53             int r = bi(i, l, n, val); 
54             mp[val] += r - l + 1;
55             l = r + 1;
56         }
57     }
58     int q, x;
59     scanf_s("%d", &q);
60     while (q--) {
61         scanf_s("%d", &x);
62         printf("%I64d\n", mp[x]);
63     }
64     return 0; 
65 }

 

posted @ 2020-06-23 21:40  吉吉的奥利奥  阅读(150)  评论(0编辑  收藏  举报