HDU 6102 GCDispower
原题连接
http://acm.hdu.edu.cn/showproblem.php?pid=6102
给定数组 P[]
m
次询问。每次给定[L,R] 计算
∑L≤i<j<k≤R[gcd(Pi,Pj)=Pk]Pk
我们记
G(L,R)=∑L≤i<j<k≤R[gcd(Pi,Pj)=Pk]Pk
前
n
个数
对于所有的L∈[1,c] ,
c∈[1,n]
A[n][c] 为 : i=c,k=n,j∈[c+1,n−1] , gcd(Pi,Pj)=Pk 对 G(L,n) 的贡献。
我们认为:
A[n][n+t]=0,t>=0
则有:
G(L,R)=∑t=1R∑k=LRA[t][k]=∑t=1R∑k=LtA[t][k]
我们可以用 O(nlog2Pi) 的时间计算出来 A[i][]
当: gcd(Pi,Pj)=Pk 时,则: PiPk⊥PjPk
那么对于 A[i][k]
区间 [i+1,k−1] 上,等于 ay∗Pk 的数组成了一个序列。
我们记
f(n)
为此时
a[]
中,与
PiPk
的最大公约数为
n
的元素个数。
F(n) 为此时
a[]
中,与
PiPk
的最大公约数为
n
的倍数的元素个数。
那么:A[i][k]=f(1)∗Pk
则:
F(n)=∑n|df(d)
f(n)=∑n|dμ(dn)F(d)
所以:
f(1)=∑d>=1u(d)F(d)
当 d∤PiPk 时 , F(d)=f(d)=0
所以:
f(1)=∑d|PiPkμ(d)F(d)
当 d|PiPk 时, F(d)=(a[]中,d的倍数的个数)
所以:
A[i][k]=Pk∑d|PiPk(μ(d)∗(a[]中,d的倍数的个数))
计算一个 A[i][k] 需要 O(log2Pk)
Pi 为 Pk 倍数的时候才会贡献。
所以。需要计算 A[][k] 的时间为 ⌊nPk⌋ 个。
总时间为
∑i=1nO(nlog2Pi)<O(nlog3)
A
只需要开一维。我们将A 中的历史贡献维护进来.
离线存储询问。在计算 A <script type="math/tex" id="MathJax-Element-49">A</script>的过程中。回答对应的询问。
下面是代码:
注意:实现的过程会有一些细节。大家要想清楚
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <vector>
#define MAXN 110005
using namespace std;
typedef long long LL;
struct arry//树状数组
{
LL A[MAXN];
int n;
void clear()
{
fill(A,A+n+5,0);
}
arry()
{
memset(A,0,sizeof A);
n=0;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,LL key)
{
while(x<=n)
{
A[x]+=key;
x+=lowbit(x);
}
}
LL sum(int x)//查询前x个元素
{
LL tmp=0;
while(x>0)
{
tmp+=A[x];
x-=lowbit(x);
}
return tmp;
}
LL get(int L,int R)
{
return sum(R)-sum(L-1);
}
}A;
struct pai
{
int L,R,id;
pai(int L,int R,int id):L(L),R(R),id(id){}
pai()
{
*this=pai(0,0,0);
}
bool operator <(const pai& A)const
{
return R<A.R;
}
}Q[MAXN];//离线问题
void init();//初始化,计算莫比乌斯函数 与 区间因式分解
vector<int>V[MAXN];// 用于存储 因式分解。
int u[MAXN];//莫比乌斯函数
void getMu()
{
int n=MAXN;
for(int i=1;i<n;i++)
{
int target= i==1 ? 1 : 0;
int delta = target-u[i];
u[i]=delta;
for(int j=i+i;j<n;j+=i) u[j]+=delta;
}
}
int F[MAXN];
int X[MAXN];
int P[MAXN];
LL ans[MAXN];
int D[MAXN];
int main ()
{
init();
int t,n,q,L,R;
scanf("%d",&t);
while(t--)
{
A.clear();
scanf("%d %d",&n,&q);
A.n=n;
n++;
for(int i=1;i<n;i++) scanf("%d",P+i);
for(int i=1;i<n;i++) X[P[i]]=i;
for(int i=0;i<q;i++)
{
scanf("%d %d",&L,&R);
Q[i]=pai(L,R,i);
}
sort(Q,Q+q);
int count=0;
for(int i=1;i<n;i++)
{
int size=n/P[i]+1;
fill(F,F+size+1,0);
int deep=0;
for(int j=P[i];j<n;j+=P[i])
{
if(X[j]>i)continue;
D[deep++]=X[j];
}
sort(D,D+deep);
deep--;
while((--deep)>-1)
{
int x=D[deep];
int t=P[x]/P[i];
LL bu=0;
for(int d=0;d<V[t].size();d++) bu+=(LL)u[V[t][d]]*F[V[t][d]];
A.add(x,bu*P[i]);
//printf("%lld\n",bu*P[i]);
for(int d=0;d<V[t].size();d++) F[V[t][d]]++;
}
while(Q[count].R==i&&count<q)
{
ans[Q[count].id]=A.get(Q[count].L,Q[count].R);
count++;
}
}
for(int i=0;i<q;i++) printf("%lld\n",ans[i]);
}
return 0;
}
void init()
{
getMu();
for(int i=1;i<MAXN;i++)
for(int j=i;j<MAXN;j+=i)
V[j].push_back(i);
}