• 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 }

     

  • 相关阅读:
    Java学习
    Java学习
    Vue.js学习(十五)—— ref和$refs的使用
    Vue.js学习(十四)—— Vue中的导航守卫(路由守卫)
    Vue.js学习(十二)—— Vue 全局挂载自定义函数
    Vue.js学习(十一)—— 项目开始、首页入门(main.js)
    Vue.js学习(十)—— element-ui 实战各种小技巧(长期更新)(转)
    Vue.js学习(九)—— normalize.css在vue中使用
    Vue.js学习(七)—— Vue开发与调试工具之vscode
    Vue.js学习(六)—— 轻量级JS Cookie插件
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5687347.html
Copyright © 2020-2023  润新知