• hdu 5726 GCD


    题意:

    给出一个数组,每次询问区间[l,r]的gcd是多少,并且这个数组有多少个连续的区间的gcd和[l,r]的gcd相等。

    思路:

    区间询问RMQ问题,可以用st表解决,预处理的时间是O(nlogn),一次查询的时间是O(logn)。

    关键是第二个问题,如何找出这些区间的数量。

    如果固定区间的左端点,那么随着区间长度的增大,gcd肯定是非递增的,减少的话一定是每次至少减少1/2,所以一个区间内的gcd最多有log(1e9)个。

    所以固定左端点,二分当前的gcd能达到的最远的右端点的位置,然后加到一个map当中进行维护,这也是一个预处理,那么每次就可以o(logn)进行回答。

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <math.h>
     5 #include <map>
     6 using namespace std;
     7 typedef long long ll;
     8 const int N = 1e5 + 10;
     9 int a[N],dp[N][32];
    10 map<int,ll> mmp;
    11 int gcd(int x,int y)
    12 {
    13     return y ? gcd(y,x%y) : x; 
    14 }
    15 void init(int n)
    16 {
    17     mmp.clear();
    18     for (int i = 0;i < n;i++)
    19     {
    20         dp[i][0] = a[i];
    21     }
    22     int bitn = (int)(log(n)/log(2.0));
    23     for (int j = 1;j <= bitn;j++)
    24     {
    25         for (int i = 0;i < n;i++)
    26         {
    27             if (i + (1 << j) - 1 >= n) break;
    28             dp[i][j] = gcd(dp[i][j-1],dp[i+(1 << (j-1))][j-1]);
    29         }
    30     }
    31 }
    32 int que(int l,int r)
    33 {
    34     int k = (int)(log(r-l+1.0) / log(2.0));
    35     return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
    36 }
    37 int main()
    38 {
    39     int T;
    40     scanf("%d",&T);
    41     int kase = 0;
    42     while (T--)
    43     {
    44         int n;
    45         scanf("%d",&n);
    46         for (int i = 0;i < n;i++) scanf("%d",&a[i]);
    47         printf("Case #%d:
    ",++kase);
    48         init(n);
    49         for (int i = 0;i < n;i++)
    50         {
    51             int j = i;
    52             while (j < n)
    53             {
    54                 int tmp = que(i,j);
    55                 int l = j,r = n;
    56                 while (r - l > 1)
    57                 {
    58                     int mid = (l + r) >> 1;
    59                     if (que(i,mid) == tmp) l = mid;
    60                     else r = mid;
    61                 }
    62                 mmp[tmp] += l - j + 1;
    63                 j = l + 1;
    64             }
    65         }
    66         int q;
    67         scanf("%d",&q);
    68         while (q--)
    69         {
    70             int l,r;
    71             scanf("%d%d",&l,&r);
    72             l--,r--;
    73             int ans = que(l,r);
    74             printf("%d %lld
    ",ans,mmp[ans]);
    75         }
    76     }
    77     return 0;
    78 }
  • 相关阅读:
    自定义控件绘制画圆
    SQLite Database Browser 2.0使用方法
    C#学习基础概念二十五问
    C# 导出Excel的示例
    三元表达式
    界面布局(上)
    C# 反射总结
    结对作业第二次
    代码复审
    继Junit....
  • 原文地址:https://www.cnblogs.com/kickit/p/9058549.html
Copyright © 2020-2023  润新知