传送门
题解:
首先很显然地,我们发现题目的限制可以转化为 f ( a , b ) a b = f ( b , a ) a b = f ( a , a + b ) a ( a + b ) \frac{f(a,b)}{ab}=\frac{f(b,a)}{ab}=\frac{f(a,a+b)}{a(a+b)} abf(a,b)=abf(b,a)=a(a+b)f(a,a+b)
进而发现,对于任意 a , b a,b a,b,我们可以得到 g ( g c d ( a , b ) ) = f ( a , b ) a b g(gcd(a,b))=\frac{f(a,b)}{ab} g(gcd(a,b))=abf(a,b),也就是说,所有 g c d gcd gcd相同的数对是捆绑在一起的。
那么我们现在需要求的就是
A n s = ∑ i = 1 n ∑ j = 1 n i j ⋅ g ( g c d ( i , j ) ) = ∑ k = 1 n g ( k ) k 2 ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ i ⋅ j [ g c d ( i , j ) = 1 ] = ∑ k = 1 n g ( k ) k 2 ∑ i = 1 ⌊ n k ⌋ i 2 ϕ ( i ) \begin{aligned} Ans=&\sum_{i=1}^n\sum_{j=1}^nij\cdot g(gcd(i,j))\\ =&\sum_{k=1}^ng(k)k^2\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{k}\rfloor}i\cdot j[gcd(i,j)=1]\\ =&\sum_{k=1}^ng(k)k^2\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i^2\phi(i) \end{aligned} Ans===i=1∑nj=1∑nij⋅g(gcd(i,j))k=1∑ng(k)k2i=1∑⌊kn⌋j=1∑⌊kn⌋i⋅j[gcd(i,j)=1]k=1∑ng(k)k2i=1∑⌊kn⌋i2ϕ(i)
发现总共有 O ( m ) O(m) O(m)个修改和 O ( m n ) O(m\sqrt n) O(mn)个查询。
用分块来修改就可以做到严格的 O ( m n ) O(m\sqrt n) O(mn)加上预处理的 O ( n ) O(n) O(n),可以轻松通过本题。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
inline ll gl(){return get<ll>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
int n,m;
cs int N=4e6+7;
int p[N],pc;
bool mark[N];
int phi[N],f[N];
inline void linear_sieves(){
phi[1]=1;f[1]=1;
for(int re i=2;i<=n;++i){
if(!mark[i])p[++pc]=i,phi[i]=i-1;
for(int re j=1;i*p[j]<=n;++j){
mark[i*p[j]]=true;
if(i%p[j])phi[i*p[j]]=phi[i]*(p[j]-1);
else {
phi[i*p[j]]=phi[i]*p[j];
break;
}
}
f[i]=add(f[i-1],mul(mul(i,i),phi[i]));
}
}
cs int B=2e4+7;
int bsiz,bcnt;
int bl[N],pl[B],pr[B],tag[B],val[N],now[N];
inline int query(int i){
return add(val[i],tag[bl[i]]);
}
signed main(){
#ifdef zxyoi
freopen("table.in","r",stdin);
#endif
m=gi(),n=gi();linear_sieves();
bsiz=std::max(0.5*sqrt(n),1.);
for(int re i=1;i<=n;++i){
if((i-1)%bsiz==0){
pr[bcnt]=i-1;
pl[++bcnt]=i;
}
bl[i]=bcnt;
val[i]=add(val[i-1],now[i]=mul(i,i));
}pr[bcnt]=n;
while(m--){
int a=gi(),b=gi();ll x=gl();int k=gi();
int g=std::__gcd(a,b);
int d=(x/(a/g)/(b/g))%mod;
int ad=dec(d,now[g]);
now[g]=d;
for(int re i=g;i<=pr[bl[g]];++i)Inc(val[i],ad);
for(int re i=bl[g]+1;i<=bcnt;++i)Inc(tag[i],ad);
int ans=0;
for(int re l=1,r;l<=k;l=r+1){
r=k/(k/l);
Inc(ans,mul(dec(f[r],f[l-1]),query(k/l)));
}
cout<<ans<<"\n";
}
return 0;
}