# 【BZOJ4815】[CQOI2017]小Q的表格（莫比乌斯反演，分块）

## 题解

\begin{aligned}b*f(a,a+b)&=(a+b)*f(a,b)\\\frac{f(a,a+b)}{a+b}&=\frac{f(a,b)}{b}\\\frac{f(a,a+b)}{a*(a+b)}&=\frac{f(a,b)}{a*b}\end{aligned}

$\frac{f(a,c)}{a*c}=\frac{f(a,c-a)}{a*(c-a)}$

$\frac{f(a,b)}{a*b}=\frac{f(a,a\%b)}{a*(a\%b)}$

$\frac{f(a,b)}{a*b}=\frac{f(gcd(a,b),gcd(a,b)}{gcd^2(a,b)}$

$f(a,b)=\frac{a*b}{d^2}f(d,d)$

\begin{aligned}ans&=\sum_{i=1}^k\sum_{j=1}^kf(i,j)\\&=\sum_{d=1}^kf(d,d)\sum_{i=1}^k\sum_{j=1}^k\frac{i*j}{d^2}[gcd(i,j)=d]\\&=\sum_{d=1}^kf(d,d)\sum_{i=1}^{k/d}\sum_{j=1}^{k/d}ij[gcd(i,j)=1]\end{aligned}

\begin{aligned}\sum_{i=1}^n\sum_{j=1}^nij[gcd(i,j)=1]&=2*\sum_{i=1}^ni\sum_{j=1}^ij[gcd(i,j)=1]\\&=2*\sum_{i=1}^n\frac{i\varphi(i)}{2}\\&=\sum_{i=1}^ni^2\varphi(i)\end{aligned}

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MOD 1000000007
#define MAX 4000400
#define BLK 2200
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int phi[MAX],pri[MAX],tt,s[MAX];
bool zs[MAX];
void Pre(int n)
{
phi[1]=1;
for(int i=2;i<=n;++i)
{
if(!zs[i])pri[++tt]=i,phi[i]=i-1;
for(int j=1;j<=tt&&i*pri[j]<=n;++j)
{
zs[i*pri[j]]=true;
if(i%pri[j])phi[i*pri[j]]=phi[i]*(pri[j]-1);
else{phi[i*pri[j]]=phi[i]*pri[j];break;}
}
}
for(int i=1;i<=n;++i)s[i]=1ll*i*i%MOD*phi[i]%MOD;
for(int i=1;i<=n;++i)s[i]=(s[i]+s[i-1])%MOD;
}
int pre[BLK],ps[BLK],bs[BLK][BLK],val[MAX];
int b[MAX],tot,blk;
int n,m;
int Query(int x){if(!x)return 0;return (pre[b[x]-1]+bs[b[x]][x-blk*(b[x]-1)])%MOD;}
void Modify(int x,int w)
{
val[x]=w;int p=x-blk*(b[x]-1);
for(int i=x;b[i]==b[x];++i,++p)
bs[b[x]][p]=(bs[b[x]][p-1]+val[i])%MOD;
ps[b[x]]=bs[b[x]][p-1];
for(int i=1;i<=tot;++i)pre[i]=(pre[i-1]+ps[i])%MOD;
}
int Calc(int k)
{
int ret=0;
for(int i=1,j;i<=k;i=j+1)
{
j=k/(k/i);
ret=(ret+1ll*(Query(j)-Query(i-1)+MOD)*s[k/i])%MOD;
}
return ret;
}
int main()
{
for(int i=1;i<=n;++i)b[i]=(i-1)/blk+1;
tot=b[n];
for(int i=1;i<=n;++i)val[i]=1ll*i*i%MOD;
for(int i=1;i<=tot;++i)
for(int j=1,a=(i-1)*blk+1;j<=blk&&a<=n;++j,++a)
ps[i]=(ps[i]+val[a])%MOD,bs[i][j]=(bs[i][j-1]+val[a])%MOD;
for(int i=1;i<=tot;++i)pre[i]=(pre[i-1]+ps[i])%MOD;
while(m--)
{