The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 645 Accepted Submission(s): 279
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
Author
SXYZ
Source
在网上找了很多莫队算法的资料,感觉就这个最好懂Mo's algorithm
这场多校是中学生出的。。。应该是之前中学生被人抱怨出题太难,所以这题数据范围放小了,常数小的O(n^2)算法就能800ms水过。。(每次处理出第r个数的logn段gcd区间直接向前遍历一遍更新所有[i,r]的答案),莫队算法只用180ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
typedef long long LL;
#define fir first
#define sec second
const int maxn=1e5+10;
int n,m,a[maxn];
int siz,num;
struct Query
{
int l, r, id;
int st;
bool operator < (const Query& a) const
{
return st!=a.st ? st<a.st : r<a.r;
}
};
Query q[maxn];
vector<P> seg[maxn], segr[maxn];
int gcd(int a, int b)
{
int tmp;
while(b){
tmp=a%b;
a=b;
b=tmp;
}
return a;
}
LL ans[maxn];
int main()
{
int t;
cin>>t;
while(t--){
cin>>n;
for(int i=0; i<=n; i++) seg[i].clear(), segr[i].clear();
for(int i=0; i<n; i++) scanf("%d", a+i);
siz=sqrt(n);
num=(n+siz-1)/siz;
cin>>m;
for(int i=0; i<m; i++){
scanf("%d%d", &q[i].l, &q[i].r);
q[i].l--; q[i].r--;
q[i].id=i;
q[i].st=q[i].l/siz;
}
sort(q, q+m);
for(int i=0; i<n; i++){
if(i)
for(int j=0; j<seg[i-1].size(); j++){
int v=gcd(seg[i-1][j].sec, a[i]);
int tot=seg[i].size();
if(tot && seg[i][tot-1].sec==v)
seg[i][tot-1].fir=seg[i-1][j].fir;
else
seg[i].push_back(P(seg[i-1][j].fir, v));
}
int tot=seg[i].size();
if(tot && seg[i][tot-1].sec==a[i])
seg[i][tot-1].fir=i;
else seg[i].push_back(P(i, a[i]));
}
for(int i=n-1; i>=0; i--){
for(int j=0; j<segr[i+1].size(); j++){
int v=gcd(segr[i+1][j].sec, a[i]);
int tot=segr[i].size();
if(tot && segr[i][tot-1].sec==v)
segr[i][tot-1].fir=segr[i+1][j].fir;
else
segr[i].push_back(P(segr[i+1][j].fir, v));
}
int tot=segr[i].size();
if(tot && segr[i][tot-1].sec==a[i])
segr[i][tot-1].fir=i;
else segr[i].push_back(P(i, a[i]));
}
int l=0,r=0;
LL val=a[0];
for(int i=0; i<m; i++){
while(r<q[i].r){
r++;
for(int j=seg[r].size()-1; j>=0; j--){
if(j &&l<=seg[r][j-1].first){
val+=(LL)seg[r][j].sec*(seg[r][j].fir-seg[r][j-1].fir);
}
else{
val+=(LL)seg[r][j].sec*(seg[r][j].fir-l+1);
break;
}
}
}
while(r>q[i].r){
for(int j=seg[r].size()-1; j>=0; j--){
if(j &&l<=seg[r][j-1].fir){
val-=(LL)seg[r][j].sec*(seg[r][j].fir-seg[r][j-1].fir);
}
else{
val-=(LL)seg[r][j].sec*(seg[r][j].fir-l+1);
break;
}
}
r--;
}
while(l<q[i].l){
for(int j=segr[l].size()-1; j>=0; j--){
if(j &&r>=segr[l][j-1].fir){
val-=(LL)segr[l][j].sec*(segr[l][j-1].fir-segr[l][j].fir);
}
else{
val-=(LL)segr[l][j].sec*(r-segr[l][j].fir+1);
break;
}
}
l++;
}
while(l>q[i].l){
l--;
for(int j=segr[l].size()-1; j>=0; j--){
if(j &&r>=segr[l][j-1].fir){
val+=(LL)segr[l][j].sec*(segr[l][j-1].fir-segr[l][j].fir);
}
else{
val+=(LL)segr[l][j].sec*(r-segr[l][j].fir+1);
break;
}
}
}
ans[q[i].id]=val;
}
for(int i=0; i<m; i++)
printf("%I64d\n", ans[i]);
}
return 0;
}