Sum Of Gcd
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 513 Accepted Submission(s): 222
Problem Description
Given you a sequence of number a
1, a
2, ..., a
n, 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.
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 a 1,a 2,...,a n.
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.
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 a 1,a 2,...,a n.
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.
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
Source
题意:有一个数列,是1~n的排列。然后有Q个询问,询问[L,R]中所有gcd(a[i],a[j]) i<j 之和。
思路:
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
#define LL long long
#define clr(a,x) memset(a,x,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mp make_pair
#define Fout(file) freopen(file,"w",stdout)
#define Fin(file) freopen(file,"r",stdin)
const int maxn=20000+5;
int n,Q;
struct Point
{
int x,y,id;
Point(int x=0,int y=0,int id=0)
:x(x),y(y),id(id) { }
bool operator<(const Point&a) const
{
if(a.x==x) return y>a.y;
return x<a.x;
}
}pt[maxn],cpy[maxn];
struct SegmentTree
{
int minimal[maxn<<2],id[maxn<<2];
int tree_size;
void PushUp(int rt)
{
if(minimal[rt<<1]>minimal[rt<<1|1]) minimal[rt]=minimal[rt<<1|1],id[rt]=id[rt<<1|1];
else minimal[rt]=minimal[rt<<1],id[rt]=id[rt<<1];
}
void init() { clr(minimal,0x3f); clr(id,-1); }
void update(int p,int x,int id)
{
p+=tree_size; if(minimal[p]<=x) return;
minimal[p]=x; this->id[p]=id;
p>>=1;
while(p>=1) {
PushUp(p);
p>>=1;
}
}
int query(int l,int r)
{
l+=tree_size; r+=tree_size;
int ret=-1;
while(l<=r) {
if(l&1) {
if(id[l]!=-1) {
if(ret==-1) ret=id[l];
else if(pt[ret].x+pt[ret].y>pt[id[l]].x+pt[id[l]].y)
ret=id[l];
}
++l;
}
if(~r&1) {
if(id[r]!=-1) {
if(ret==-1) ret=id[r];
else if(pt[ret].x+pt[ret].y>pt[id[r]].x+pt[id[r]].y)
ret=id[r];
}
--r;
}
l>>=1; r>>=1;
}
return ret;
}
}segtree;
struct Edge
{
int u,v,cost;
Edge(int u=0,int v=0,int cost=0)
:u(u),v(v),cost(cost) { }
bool operator<(const Edge&e) const { return cost<e.cost; }
}edges[maxn<<3];
int e_cnt;
struct Node
{
int v;
Node *next;
}*first[maxn],edge[maxn<<1];
int ptr;
void add(int u,int v)
{
edge[++ptr].v=v;
edge[ptr].next=first[u];
first[u]=&edge[ptr];
}
int a[maxn],b[maxn];
bool cmp_a(int x,int y) { return a[x]<a[y]; }
int Bin(int x,int l,int r)
{
int m;
while(l<=r) {
m=(l+r)>>1;
if(a[b[m]]==x) return m;
else if(a[b[m]]<x) l=m+1;
else r=m-1;
}
return l;
}
int find(int x)
{
if(x==b[x]) return x;
return b[x]=find(b[x]);
}
void swap(int&a,int&b) { a^=b; b^=a; a^=b; }
void MST(int n)
{
e_cnt=0;
for(int dir=0;dir<4;++dir) {
if(dir==1||dir==3) for(int i=0;i<n;++i) swap(pt[i].x,pt[i].y);
else if(dir==2) for(int i=0;i<n;++i) pt[i].x=-pt[i].x;
sort(pt,pt+n);
segtree.init();
for(int i=0;i<n;++i) a[i]=pt[i].y-pt[i].x,b[i]=i;
sort(b,b+n,cmp_a);
int c=1;
for(int i=1;i<n;++i)
if(a[b[i]]!=a[b[i-1]]) b[c++]=b[i];
int & sz=segtree.tree_size;
sz=1; while(sz<c) sz<<=1; --sz;
for(int i=n-1;i>=0;--i) {
int h=Bin(pt[i].y-pt[i].x,0,c-1)+1;
int x=segtree.query(h,c);
if(x!=-1) edges[e_cnt++]=Edge(pt[i].id,pt[x].id,pt[x].y+pt[x].x-pt[i].x-pt[i].y);
segtree.update(h,pt[i].x+pt[i].y,i);
}
}
sort(edges,edges+e_cnt);
for(int i=0;i<n;++i) b[i]=i;
clr(first,0); ptr=0;
int len=0; int rest=n-1;
for(int i=0;i<e_cnt;++i) {
Edge&e=edges[i];
if(find(e.u)==find(e.v)) continue;
b[find(e.u)]=find(e.v);
add(e.u,e.v); add(e.v,e.u);
len+=e.cost;
if(--rest==0) break;
}
}
LL u[maxn],w[maxn];
int factor[maxn][85],sz[maxn];
void divide_factor(int x)
{
sz[x]=0;
for(LL i=1;i*i<=x;++i) {
if(x%i) continue;
factor[x][sz[x]++]=x/i;
if(i!=x/i) factor[x][sz[x]++]=i;
}
}
int cal_mu(int x)
{
int odd=1;
for(LL i=2;i*i<=x;++i) {
int cnt=0;
while(x%i==0) {
x/=i;
++cnt;
}
if(cnt>1) return 0;
else if(cnt==1) odd=-odd;
}
if(x>1) odd=-odd;
return odd;
}
void pre_init()
{
u[1]=1;
factor[1][0]=1; sz[1]=1;
for(int i=2;i<=20000;++i) {
divide_factor(i);
u[i]=cal_mu(i);
}
for(int i=1;i<=20000;++i) {
w[i]=0;
for(int j=0;j<sz[i];++j) {
w[i]+=u[factor[i][j]]*i/factor[i][j];
}
}
}
int val[maxn];
char ch;
void read_int(int & x)
{
ch=getchar(); x=0;
while(ch<'0'||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9') x=10*x+ch-'0',ch=getchar();
}
LL num[maxn];
LL ans;
LL output[maxn];
void update(int x,LL sign)
{
for(int i=0;i<sz[x];++i) {
int y=factor[x][i];
ans=ans+sign*num[y]*w[y];
if(sign<0) ans+=w[y];
num[y]+=sign;
}
}
void input()
{
scanf("%d",&n);
for(int i=0;i<n;++i) read_int(val[i]);
scanf("%d",&Q);
for(int i=0;i<Q;++i) {
read_int(pt[i].x); read_int(pt[i].y);
pt[i].id=i; cpy[i]=pt[i]; --cpy[i].x; --cpy[i].y;
}
}
void dfs(int id,int l,int r,int fa)
{
int L=pt[id].x,R=pt[id].y;
int l0=l,r0=r;
while(r0<R) { ++r0; update(val[r0],1); }
while(r0>R) { update(val[r0],-1); --r0; }
while(l0>L) { --l0; update(val[l0],1); }
while(l0<L) { update(val[l0],-1); ++l0; }
output[id]=ans;
for(Node*p=first[id];p;p=p->next) {
int nxt=p->v;
if(nxt==fa) continue;
dfs(nxt,l0,r0,id);
}
while(r0<r) { ++r0; update(val[r0],1); }
while(r0>r) { update(val[r0],-1); --r0; }
while(l0>l) { --l0; update(val[l0],1); }
while(l0<l) { update(val[l0],-1); ++l0; }
}
void solve()
{
for(int i=0;i<Q;++i) pt[i]=cpy[i];
dfs(0,pt[0].x,pt[0].x-1,-1);
for(int i=0;i<Q;++i)
printf("%I64d\n",output[i]);
}
int main()
{
pre_init();
int T;cin>>T;
for(int Cas=1;Cas<=T;++Cas) {
ans=0;
input();
MST(Q);
printf("Case #%d:\n",Cas);
solve();
}
}