HDU 5381 The sum of gcd (技巧,莫队算法)

  我以为稍微水一下O(n2)还是可以过的,毕竟只有3个test case。死活不让啊。

 1 #include <bits/stdc++.h>
 2 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
 3 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
 4 #define pii pair<int,int>
 5 #define INF 0x7f7f7f7f
 6 #define LL long long
 7 using namespace std;
 8 const int N=10005;
 9 struct node
10 {
11     int L, R, ans;
12 }que[N];
13 struct node1
14 {
15     int ll, rr, gcd;
16     node1(){};
17     node1(int ll,int rr,int gcd):ll(ll),rr(rr),gcd(gcd){};
18 }reg[N][50];
19
20 int _gcd(int a, int b){return b == 0 ? a : _gcd(b, a % b);}
21
22 int seq[N], n, q, pre[N];
23 int cnt[N];
24 void pre_cal()
25 {
26     memset(cnt,0,sizeof(cnt));
27     reg[n][0]=node1(n,n,seq[n]); //最后一个特殊处理
28     cnt[n]++;
29     for(int i=n-1; i>=1; i--)
30     {
31         int R=i, gcd=seq[i], tmp;
32         for(int j=0; j<cnt[i+1]; j++)
33         {
34             node1 &t=reg[i+1][j];
35             tmp=_gcd(gcd, t.gcd );
36             if(tmp!=gcd)    reg[i][cnt[i]++]=node1(i, R, gcd);
37             gcd=tmp;
38             R=t.rr;
39         }
40         reg[i][cnt[i]++]=node1(i, R, gcd);
41     }
42 }
43
44 void cal()
45 {
46     for(int i=1; i<=n; i++)
47     {
48         pre[i-1]=0;
49         pre[i]=seq[i];
50         int p=0;
51         for(int j=i+1; j<=n; j++)
52         {
53             if(j>reg[i][p].rr)  p++;
54             pre[j]=reg[i][p].gcd;
55             pre[j]+=pre[j-1];
56         }
57         for(int j=1; j<=q; j++)
58             if( i>=que[j].L && i<=que[j].R )
59                 que[j].ans+=pre[que[j].R]-pre[i-1];
60     }
61     for(int i=1; i<=q; i++)    printf("%d\n",que[i].ans);
62 }
63 int main()
64 {
65     //freopen("input.txt", "r", stdin);
66     int t, L, R;
67     cin>>t;
68     while(t--)
69     {
70         scanf("%d", &n);
71         for(int i=1; i<=n; i++)    scanf("%d", &seq[i]);
72
73         scanf("%d", &q);
74         for(int i=1; i<=q; i++)
75         {
76             scanf("%d %d", &que[i].L, &que[i].R);
77             que[i].ans=0;
78         }
79         pre_cal();
80         cal();
81     }
82
83     return 0;
84 }

TLE代码

时间: 2024-10-09 21:26:24

HDU 5381 The sum of gcd (技巧,莫队算法)的相关文章

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>

(预处理+莫队算法)HDU - 5381 The sum of gcd

题意: 一个长度为n的数列,m次查询L到R之间所有连续子序列的gcd之和. 分析: 很明显的莫队算法. 很明显发现了gcd是单调递减的,并且最多存在32个的性质. 想了很久,脑补了许多种方法来拉伸L和R,但是都有漏洞. 实际上,这道题还是比较复杂的.. 在思考的过程中,我没有充分利用gcd的递减性质. 这题其实这题有共通之处,至少在我的做法上是这样的. 可以发现,在R向右拉伸的过程中,增加的和只是从L到R+1中的每一个后缀的和. 向左则为减,L的移动同理. 那么我们只要提前预处理每个位置的前缀所

HDU 5381 The sum of gcd (2015年多校比赛第8场)

1.题目描述:点击打开链接 2.解题思路:本题利用莫队算法解决.由于是第一次学习这个算法,因此研究了比较长的一段时间才弄懂.首先,莫队算法解决的问题是无修改的离线区间查询问题.该算法实际上是由曼哈顿距离最小生成树演变来的,由于要处理m个区间,可以将这m个区间看做二维平面上的点,那么处理这m个区间就等价于让这m点连通,且总的转移代价最小.这其实就是一个曼哈顿距离最小生成树问题. 经典的曼哈顿距离最小生成树的时间复杂度是O(NlogN),莫队算法的时间复杂度是O(N^1.5).不过本题还有一个地方,

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

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

对于每个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对所

hdu 5381 The sum of gcd(线段树等差数列区间修改+单点查询)

题意: 给出一个数组a,叫你每次询问如下等式的值. f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj) 解析: 思考了很久终于理解了学长的思路 给你一个序列,这个序列的子序列gcd的个数不会超过logN个(N为每个数字,最大能取到的范围) 因为求gcd是递减的,每次至少除以2,所以gcd的个数只会有logN个. 然后让我们来看看题目要求的是什么. 所有子区间的gcd的和. 比如[1, 5]这个区间可以分解成如下子区间. [1, 1] [1, 2] [1, 3] [1, 4]

【树状数组】HDU 5381 The sum of gcd

通道 题意:f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj),q次询问. 代码: