hdu5381 The sum of gcd

  莫队算法,预处理出每个数字往后的gcd情况,每个数字的gcd只可能是他的因子,因此后面最多只可能有logn种,可以先预处理出,然后套莫队算法,复杂度O(n*sqrt(n)*log(n))。

  

  代码

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<vector>
  4 #include<algorithm>
  5 #define N 100000
  6 using namespace std;
  7 int n,q,s[N][16],i,j,tmp,l,r;
  8 long long ans,Ans[N];
  9 vector<pair<int,int> > vec0[N],vec1[N];
 10 struct g
 11 {
 12     int l,r,t,id;
 13 }Q[N];
 14 bool cmp(g a,g b)
 15 {
 16     if (a.t==b.t)
 17         return a.r<b.r;
 18     return a.t<b.t;
 19 }
 20 int gcd(int a,int b)
 21 {
 22     if (b==0) return a;
 23     return gcd(b,a%b);
 24 }
 25 int GCD(int a,int b)
 26 {
 27     int k;
 28     k=log2(b-a+1);
 29     return gcd(s[a][k],s[b-(1<<k)+1][k]);
 30 }
 31 int ef(int i,int l,int r,int x)
 32 {
 33     int m;
 34     while (l<=r)
 35     {
 36         m=(l+r)>>1;
 37         if (GCD(i,m)==x) l=m+1;else r=m-1;
 38     }
 39     return l;
 40 }
 41 int EF(int i,int l,int r,int x)
 42 {
 43     int m;
 44     while (l<=r)
 45     {
 46         m=(l+r)>>1;
 47         if (GCD(m,i)==x) r=m-1;else l=m+1;
 48     }
 49     return r;
 50 }
 51 long long calc(int l,int r)
 52 {
 53     long long ans=0;
 54     int len,t,i;
 55     if (l<r)
 56     {
 57         len=vec0[l].size();
 58         t=l;
 59         for (i=0;i<len;i++)
 60         {
 61             ans+=1LL*(min(r,vec0[l][i].second)-t+1)*vec0[l][i].first;
 62             t=vec0[l][i].second+1;
 63             if (t>r) break;
 64         }
 65     }
 66     else
 67     {
 68         len=vec1[l].size();
 69         t=l;
 70         for (i=0;i<len;i++)
 71         {
 72             ans+=1LL*(t-max(r,vec1[l][i].second)+1)*vec1[l][i].first;
 73             t=vec1[l][i].second-1;
 74             if (t<r) break;
 75         }
 76     }
 77     return ans;
 78 }
 79 void QL()
 80 {
 81     while (l<Q[i].l)
 82             {
 83                 ans-=calc(l,r);
 84                 l++;
 85             }
 86             while (l>Q[i].l)
 87             {
 88                 l--;
 89                 ans+=calc(l,r);
 90             }
 91 }
 92 void QR()
 93 {
 94     while (r<Q[i].r)
 95             {
 96                 r++;
 97                 ans+=calc(r,l);
 98             }
 99             while (r>Q[i].r)
100             {
101                 ans-=calc(r,l);
102                 r--;
103             }
104 }
105 int main()
106 {
107     int test;
108     scanf("%d",&test);
109     while (test--)
110     {
111     scanf("%d",&n);
112     for (i=1;i<=n;i++)
113     {
114         scanf("%d",&s[i][0]);
115         vec0[i].clear();
116         vec1[i].clear();
117     }
118     for (i=n;i>=1;i--)
119         for (j=1;j<=log2(n);j++)
120             s[i][j]=gcd(s[i][j-1],s[i+(1<<(j-1))][j-1]);
121
122     for (i=1;i<=n;i++)
123     {
124         l=i;r=n;
125         while (l<=n)
126         {
127             tmp=GCD(i,l);
128             l=ef(i,l,r,tmp);
129             vec0[i].push_back(make_pair(tmp,l-1));
130         }
131     }
132
133
134     for (i=n;i>=1;i--)
135     {
136         l=1;r=i;
137         while (r>0)
138         {
139             tmp=GCD(r,i);
140             r=EF(i,l,r,tmp);
141             vec1[i].push_back(make_pair(tmp,r+1));
142         }
143     }
144
145     scanf("%d",&q);
146     for (i=1;i<=q;i++)
147     {
148         scanf("%d%d",&Q[i].l,&Q[i].r);
149         Q[i].id=i;Q[i].t=Q[i].l/100;
150     }
151     sort(Q+1,Q+1+q,cmp);
152     l=Q[1].l;r=Q[1].r;ans=0;
153     for (i=l;i<=r;i++) ans+=calc(i,r);
154     Ans[Q[1].id]=ans;
155
156
157     for (i=2;i<=q;i++)
158     {
159         if (l<Q[i].l)
160         {
161             QR();QL();
162         }
163         else
164         {
165             QL();QR();
166         }
167         Ans[Q[i].id]=ans;
168     }
169     for (i=1;i<=q;i++)
170         printf("%I64d\n",Ans[i]);
171     }
172 }
时间: 2025-02-01 11:41:04

hdu5381 The sum of gcd的相关文章

hdu5381 The sum of gcd]莫队算法

题意:http://acm.hdu.edu.cn/showproblem.php?pid=5381 思路:这个题属于没有修改的区间查询问题,可以用莫队算法来做.首先预处理出每个点以它为起点向左和向右连续一段的gcd发生变化的每个位置,不难发现对每个点A[i],这样的位置最多logA[i]个,这可以利用ST表用nlognlogA[i]的时间预处理,然后用二分+RMQ在nlogn的时间内得到.然后就是区间变化为1时的转移了,不难发现区间变化为1时,变化的答案仅仅是以变化的那一个点作为左端点或右端点的

hdu 5381 The sum of gcd 莫队+预处理

The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description You have an array A,the length of A is nLet f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj) Input There are multiple test cases. The first line

Sum Of Gcd(hdu 4676)

Sum Of Gcd Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 738    Accepted Submission(s): 333 Problem Description Given you a sequence of number a1, a2, ..., an, which is a permutation of 1...n

HDOJ 5381 The sum of gcd 莫队算法

大神题解: http://blog.csdn.net/u014800748/article/details/47680899 The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 526    Accepted Submission(s): 226 Problem Description You have an

hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法

The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 23    Accepted Submission(s): 4 Problem Description You have an array ,the length of  is Let Input There are multiple test cases.

HDU 5381 The sum of gcd 莫队暴力

链接 题解链接:http://www.cygmasot.com/index.php/2015/08/15/hdu_5381/ 题意: 给定n长的序列 下面n个数给出这个序列 m个询问 下面m行给出询问的区间. 对于一个询问,输出这个区间内的任意子段的gcd 和. 思路: 因为一个数的gcd只会不变或下降,下降一次至少减半,下降至多32次,所以处理出每个数连续相同的gcd的区间. 然后暴力跑莫队. #pragma comment(linker, "/STACK:1024000000,1024000

hdu 5381 The sum of gcd(线段树+gcd)

题目链接:hdu 5381 The sum of gcd 将查询离线处理,按照r排序,然后从左向右处理每个A[i],碰到查询时处理.用线段树维护,每个节点表示从[l,i]中以l为起始的区间gcd总和.所以每次修改时需要处理[1,i-1]与i的gcd值,但是因为gcd值是递减的,成log级,对于每个gcd值记录其区间即可.然后用线段树段修改,但是是修改一个等差数列. #include <cstdio> #include <cstring> #include <vector>

hdu5381(2015多校8)--The sum of gcd(线段树)

题目链接:点击打开链接 题目大意:f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj),给出初始的n个值,q次询问,每次询问输出f(l,r)的值 大多都是说莫队算法,没有想出肿么用,,,,本题用两个线段树完成 首先对于任意一个a[i],每次gcd减小至少一半,所以它向后的gcd最多下降log(a[i])次,可以求出对于每一个a[i]来说的gcd相同的各个区间. 用线段树维护一段区间的gcd,可以查询一段[l,r]的gcd的值x,从i开始枚举左边界l,然后用二分查找到gcd相同的

HDU 5381 The sum of gcd

对于每个i,求出若干区间[l1,r1],[l2,r2],[l3,r3]...满足gcd(l1~i)~gcd(r1~i)一样,gcd(l2~i)~gcd(r2,i)一样... 则以i为右区间的所有gcd和为sum[i] = (r1 - l1 + 1) * g1 + (r2 - l2 + 1) * g2 + ... 同理求出i右边的一段段同gcd区间[l11,r11],[l22,r22],[l33,r33]... 然后将询问按左区间排序,int p初始设为1,对于p <= i < L,要消除i对所