The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 854 Accepted Submission(s): 363
Problem Description
You have an array
A
,the length of
A
is
n
Let f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
Let f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integers n
Second line has n integers Ai
Third line has one integers Q ,the number of questions
Next there are Q lines,each line has two integers l , r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
First line has one integers n
Second line has n integers Ai
Third line has one integers Q ,the number of questions
Next there are Q lines,each line has two integers l , r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
Output
For each question,you need to print
f(l,r)
Sample Input
2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
Sample Output
9 6 16 18 23 10
最难的不是莫队。。 而是。。 处理转移关系。。 神题
rmq可以用来预处理gcd也是第一次知道。。
利用gcd特殊性质优化
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
const int maxn = 10010;
typedef pair<int, int> pii;
typedef long long ll;
int gcd[maxn][20], mm[maxn];
int n,q,a[maxn], unit;
vector<pii> lef[maxn], rig[maxn];
ll ans[maxn];
struct node{
int l, r, id;
bool operator<(const node & b) const{
if( l/unit == b.l/unit) return r < b.r;
return l/unit < b.l/unit;
}
}Query[maxn];
void init(){
mm[0] = -1;
for(int i=1; i<=n; i++){
mm[i] = (i&(i-1)) == 0?mm[i-1]+1:mm[i-1];
gcd[i][0] = a[i];
}
for(int j=1; j<=mm[n]; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
gcd[i][j] = __gcd(gcd[i][j-1], gcd[i+(1<<(j-1))][j-1]);
}
int query(int l, int r){
int k = mm[r-l+1];
return __gcd(gcd[l][k], gcd[r-(1<<k)+1][k]);
}
void go(){
for(int i=1; i<=n; i++)
lef[i].clear(), rig[i].clear();
int ans;
for(int i=1; i<=n; i++){
int L = 1, R = i, g = a[i], mid;
while(true){
while(L<=R){
mid = (L+R)>>1;
if(query(mid, i) == g) R = mid-1, ans = mid;
else L = mid + 1;
}
lef[i].push_back(make_pair(g, ans));
if(ans == 1) break;
R = ans - 1; L = 1; g = query(R, i);
}
}
for(int i=1; i<=n; i++){
int L = i, R = n, g = a[i], mid;
while(true){
while(L <= R){
mid = (L+R+1)>>1;
if(query(i, mid) == g) L = mid+1, ans = mid;
else R = mid-1;
}
rig[i].push_back(make_pair(g, ans));
if(ans == n) break;
L = ans + 1, R = n, g = query(i, L);
}
}
}
ll LEFT(int x, int L){
int p = x;
ll ans = 0;
int size = lef[x].size();
for(int i=0; i<size; i++){
int g = lef[x][i].first, pos = max(L, lef[x][i].second);
ans += (ll)g*(ll)(p - pos + 1);
p = pos - 1;
if( p < L ) break;
}
return ans;
}
ll RIGHT(int x, int R){
int p = x;
ll ans = 0;
int size = rig[x].size();
for(int i=0; i<size; i++){
int g = rig[x][i].fi, pos = min(R, rig[x][i].se);
ans += (ll)g*(ll)(pos - p + 1);
p = pos + 1;
if( p > R) break;
}
return ans;
}
void work(){
int L = 1;
int R = 0;
sort(Query+1, Query+q+1);
ll cnt = 0;
for(int i=1; i<=q; i++){
while(R<Query[i].r)
cnt += LEFT(++R, L);
while(R>Query[i].r)
cnt -= LEFT(R--, L);
while(L<Query[i].l)
cnt -= RIGHT(L++, R);
while(L>Query[i].l)
cnt += RIGHT(--L, R);
ans[Query[i].id] = cnt;
}
}
int main(){
int T;
cin>>T;
while(T--){
cin>>n;
unit = sqrt(n);
for(int i=1; i<=n; i++)
scanf("%d", a+i);
init();
go();
scanf("%d", &q);
for(int i=1; i<=q; i++){
scanf("%d %d", &Query[i].l, &Query[i].r);
Query[i].id = i;
}
work();
for(int i=1; i<=q; i++)
printf("%I64d\n", ans[i]);
}
return 0;
}