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 }

     

  • 相关阅读:
    IIS网站应用偶尔出现"服务不可用"或者显示乱码字体
    mac os下切换pip3国内源并安装requests库
    mysql5.6运行一段时间之后网站页面出现乱码解决办法
    mac pro下安装安装 SymPy 和 matplotlib报错解决方案
    python3汉诺塔简单实现代码
    用python提取xml里面的链接源码
    Mac环境下 jieba 配置记录
    AngularJS 整理学习
    Java有关List的stream基本操作
    Callable的简单使用
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5687347.html
Copyright © 2011-2022 走看看