zoukankan      html  css  js  c++  java
  • HDU 5726 GCD

    题目:GCD

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726

    题意:给一个数组a,大小为n,接下来有m个询问,每次询问给出l、r,定义f[l,r]=gcd(al,al+1,...,ar),问f[l,r]的值 和 有多少对(l',r')使得f[l',r']=f[l,r]。n<=10万,m<=10万,1<=l<=r<=n,1<=l'<=r'。

    思路:

      第一步比较简单,预处理一下,定义f[i][j]为:ai开始,连续2^j个数的最大公约数,所以f[1][0]=a[1],f[1][1]=gcd(a1,a2),f[1][2]=gcd(a1,a2,a3,a4)。其实就是动态规划,让i从1-n,让j从0-17,递推上去即可。

      递推公式如下:

      1. f[i][0]=a[i];

      2. f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]);

      就如同f[1][2]=gcd(f[1][1],f[3][1])=gcd(gcd(f[1][0],f[2][0]),gcd(f[3][0],f[4][0]));

      通过上述预处理,查询时就只需O(logn)时间,如下:

      令k=log2(r-l+1),look(l,r)=gcd(f[l][k],f[r-(1<<k)+1][k]);

      注:f[l][k] 和 f[r-(1<<k)+1][k]可能会有重叠,但不影响最终的gcd值。

      比赛时第二步没想出来,太可惜了。。。

      第二步,我们可以枚举左端点 i 从1-n,对每个i,二分右端点,计算每种gcd值的数量,因为如果左端点固定,gcd值随着右端点的往右,呈现单调不增,而且gcd值每次变化,至少除以2,所以gcd的数量为nlog2(n)种,可以开map<int,long long>存每种gcd值的数量,注意n大小为10万,所以数量有可能爆int。

     1 #include<stdio.h>
     2 #include<math.h>
     3 #include<map>
     4 using namespace std;
     5 int f[100010][18];
     6 int a[100010];
     7 int n,m;
     8 int gcd(int a,int b)
     9 {
    10   return b?gcd(b,a%b):a;
    11 }
    12 void rmq()
    13 {
    14   for(int j=1;j<=n;j++) f[j][0]=a[j];
    15   for(int i=1;i<18;i++)
    16   {
    17     for(int j=1;j<=n;j++)
    18     {
    19       if(j+(1<<i)-1 <= n)
    20       {
    21         f[j][i]=gcd(f[j][i-1],f[j+(1<<i-1)][i-1]);
    22       }
    23     }
    24   }
    25 }
    26 int look(int l,int r)
    27 {
    28   int k=(int)log2((double)(r-l+1));
    29   return gcd(f[l][k],f[r-(1<<k)+1][k]);
    30 }
    31 map<int,long long> mp;
    32 void setTable()
    33 {
    34   mp.clear();
    35   for(int i=1;i<=n;i++)
    36   {
    37     int g=f[i][0],j=i;
    38     while(j<=n)
    39     {
    40       int l=j,r=n;
    41       while(l<r)
    42       {
    43         int mid=(l+r+1)>>1;
    44         if(look(i,mid)==g) l=mid;
    45         else r=mid-1;
    46       }
    47       mp[g]+=l-j+1;
    48       j=l+1;
    49       g=look(i,j);
    50     }
    51   }
    52 }
    53 int main()
    54 {
    55   int t,l,r;
    56   int cas=1;
    57   scanf("%d",&t);
    58   while(t--)
    59   {
    60     printf("Case #%d:
    ",cas++);
    61     scanf("%d",&n);
    62     for(int i=1;i<=n;i++)
    63     {
    64       scanf("%d",&a[i]);
    65     }
    66     rmq();
    67     setTable();
    68     scanf("%d",&m);
    69     for(int i=0;i<m;i++)
    70     {
    71       scanf("%d%d",&l,&r);
    72       int g=look(l,r);
    73       printf("%d %I64d
    ",g,mp[g]);
    74     }
    75   }
    76   return 0;
    77 }

     

  • 相关阅读:
    游标cursor
    SQL: EXISTS
    LeetCode Reverse Integer
    LeetCode Same Tree
    LeetCode Maximum Depth of Binary Tree
    LeetCode 3Sum Closest
    LeetCode Linked List Cycle
    LeetCode Best Time to Buy and Sell Stock II
    LeetCode Balanced Binary Tree
    LeetCode Validate Binary Search Tree
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5687347.html
Copyright © 2011-2022 走看看