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.
You need to answer some queries, each with the following format:
Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.

Input

First line contains a number T(T <= 10),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1<=n<= 20000).
The second line contains n number a1,a2,...,an.
The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.

Output

For each case, first you should print "Case #x:", where x indicates the case number between 1 and T.
Then for each query print the answer in one line.

Sample Input

1
5
3 2 5 4 1
3
1 5
2 4
3 3

Sample Output

Case #1:
11
4
0

思路:莫比乌兹反演+莫队;

然后后面的s(d)就是欧拉函数;

以上参考http://www.ithao123.cn/content-4754688.html

然后用莫队算法维护下;

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<string.h>
  5 #include<math.h>
  6 #include<queue>
  7 #include<vector>
  8 #include<stack>
  9 #include<set>
 10 using namespace std;
 11 typedef long long LL;
 12 int ans[100000];
 13 int mul[100000];
 14 typedef struct node
 15 {
 16     int l;
 17     int r;
 18     int id;
 19 } ss;
 20 ss ask[100000];
 21 bool cmp1(node p,node q)
 22 {
 23     return p.l < q.l;
 24 }
 25 bool cmp2(node p,node q)
 26 {
 27     return p.r < q.r;
 28 }
 29 bool prime[30000];
 30 int prime_table[30000];
 31 vector<int>vec[30000];
 32 int cnt[20005];
 33 LL answ[30000];
 34 int oula[20005];
 35 void _slove_mo(int n,int m);
 36 int main(void)
 37 {
 38     int n,m;
 39     int T;
 40     int __ca = 0;
 41     int cn = 0;
 42     mul[1] = 1;
 43     int i,j;
 44     memset(prime,0,sizeof(prime));
 45     for(i = 0; i <= 20000; i++)
 46         oula[i] = i;
 47     for(i = 2; i <= 20000; i++)
 48     {
 49         if(!prime[i])
 50         {
 51             prime_table[cn++] = i;
 52             mul[i] = -1;
 53         }
 54         for(j = 0; j < cn&&(i*prime_table[j]<=20000); j++)
 55         {
 56             if(i%prime_table[j])
 57             {
 58                 prime[i*prime_table[j]] = true;
 59                 mul[i*prime_table[j]] = -mul[i];
 60             }
 61             else
 62             {
 63                 prime[i*prime_table[j]] = true;
 64                 mul[i*prime_table[j]] = 0;
 65                 break;
 66             }
 67         }
 68     }//printf("%d\n",cn);
 69     for(i = 0; i < cn; i++)
 70     {
 71         for(j = 1; j*prime_table[i]<=20000; j++)
 72         {
 73             oula[j*prime_table[i]]/=prime_table[i];
 74             oula[j*prime_table[i]]*=(prime_table[i]-1);
 75         }
 76     }
 77     for(i = 1; i <= 20000; i++)
 78     {
 79         for(j = 1; j <= sqrt(i); j++)
 80         {
 81             if(i%j==0)
 82             {
 83                 vec[i].push_back(j);
 84                 if(i/j != j)
 85                     vec[i].push_back(i/j);
 86             }
 87         }
 88     }scanf("%d",&T);
 89     while(T--)
 90     {
 91         ++__ca; memset(cnt,0,sizeof(cnt));
 92         scanf("%d",&n);
 93         for(i = 1; i <= n; i++)
 94         {
 95             scanf("%d",&ans[i]);
 96         }
 97         scanf("%d",&m);
 98         for(i = 0; i < m; i++)
 99         {
100             scanf("%d %d",&ask[i].l,&ask[i].r);
101             ask[i].id = i;
102         }
103         sort(ask,ask+m,cmp1);
104         int id = 0;
105         int ak = sqrt(1.0*n)+1;
106         int v = ak;
107         for(i = 0; i < m; i++)
108         {
109             if(ask[i].l > v)
110             {
111                 v += ak;
112                 sort(ask+id,ask+i,cmp2);
113                 id = i;
114             }
115         }
116         sort(ask+id,ask+m,cmp2);
117         _slove_mo(n,m);
118         printf("Case #%d:\n",__ca);
119         for(i = 0; i < m; i++)
120             printf("%lld\n",answ[i]);
121
122     }return 0;
123 }
124 void _slove_mo(int n,int m)
125 {
126     int i,j;
127     LL sum = 0;
128     int xl = ask[0].l;
129     int xr = ask[0].r;
130     for(i = xl; i <= xr; i++)
131     {
132         for(j = 0; j < vec[ans[i]].size(); j++)
133         {   int x = vec[ans[i]][j];
134             sum = sum + (LL)oula[x]*(LL)cnt[x];
135             cnt[x]++;
136         }
137     }
138     answ[ask[0].id] = sum;
139     for(i = 1; i < m; i++)
140     {
141         while(xl < ask[i].l)
142         {
143             int y = ans[xl];
144             for(j = 0; j < vec[y].size(); j++)
145             {
146                 int x = vec[y][j];
147                 sum -= (LL)oula[x]*(LL)(--cnt[x]);
148             }
149             xl++;
150         }
151         while(xl > ask[i].l)
152         {
153             xl--;
154             int y = ans[xl];
155             for(j = 0; j < vec[y].size(); j++)
156             {
157                 int x = vec[y][j];
158                 sum += (LL)oula[x]*(LL)(cnt[x]++);
159             }
160         }
161         while(xr > ask[i].r)
162         {
163             int y = ans[xr];
164             for(j = 0; j < vec[y].size(); j++)
165             {
166                 int x = vec[y][j];
167                 sum -= (LL)oula[x]*(LL)(--cnt[x]);
168             }
169             xr--;
170         }
171         while(xr < ask[i].r)
172         {
173             xr++;
174             int y = ans[xr];
175             for(j = 0; j < vec[y].size(); j++)
176             {
177                 int x = vec[y][j];
178                 sum += (LL)oula[x]*(LL)(cnt[x]++);
179             }
180         }
181         answ[ask[i].id] = sum;
182     }
183 }
时间: 2024-10-13 05:45:53

Sum Of Gcd(hdu 4676)的相关文章

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(线段树+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 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

GCD HDU - 1695 (容斥原理)

GCD HDU - 1695 题意:给你5个数a,b,c,d,k.x属于[a,b]y属于[c,d]. 问你有多少对(x,y)的公约数为k.  注意(x,y)和 (y,x)视为同一对,a和c为1. 通过b/k,d/k,等价于把区间除以k,那么就变成了求有多少对(x,y)互素. 欧拉函数+容斥原理. 注意k可能为0. 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1

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

[kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus HDU - 1024

A - Max Sum Plus Plus HDU - 1024 题目链接:https://vjudge.net/contest/68966#problem/A 题目: 现在我觉得你在Ignatius.L的“Max Sum”问题上得到了一个AC.要成为一个勇敢的ACMer,我们总是挑战自己更难的问题.现在你面临着一个更加困难的问题. 给定连续的数字序列S 1,S 2,S 3,S 4 ... S x,... S n(1≤x≤n≤1,000,000,-32768≤Sx≤32767).我们定义函数su

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]