HDU 5726 GCD

題目:GCDphp

連接: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'。spa

思路:code

  第一步比較簡單,預處理一下,定義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,遞推上去便可。blog

  遞推公式以下:get

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

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

  就如同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]));map

  經過上述預處理,查詢時就只需O(logn)時間,以下:gc

  令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:\n",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\n",g,mp[g]);
74     }
75   }
76   return 0;
77 }
相關文章
相關標籤/搜索