对于n*n的数表,任意一个位置,需要满足:
f ( a , b ) = f ( b , a ) f(a,b)=f(b,a) f(a,b)=f(b,a)
b × f ( a , a + b ) = ( a + b ) ∗ f ( a , b ) b×f(a,a+b)=(a+b)*f(a,b) b×f(a,a+b)=(a+b)∗f(a,b)
每次修改一个位置,需要将相关位置全部修改且求前k行前k列的和。
将二式变化可得:
f ( a , a + b ) a ( a + b ) = f ( a , b ) a b \frac{f(a,a+b)}{a(a+b)}=\frac{f(a,b)}{ab} a(a+b)f(a,a+b)=abf(a,b)
所以
f ( a , b ) a b = f ( a , a − b ) a ( a − b ) = f ( a , a m o d b ) a ( a m o d b ) = f ( d , d ) d 2 \frac{f(a,b)}{ab}=\frac{f(a,a-b)}{a(a-b)}=\frac{f(a,a\ modb)}{a(a\ modb)}=\frac{f(d,d)}{d^2} abf(a,b)=a(a−b)f(a,a−b)=a(a modb)f(a,a modb)=d2f(d,d)
其中 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b)
所以所有 g c d ( i , j ) = g c d ( a , b ) gcd(i,j)=gcd(a,b) gcd(i,j)=gcd(a,b)的位置都会受影响。
枚举 d d d
a n s = ∑ d n f ( d ) ∑ i ⌊ n d ⌋ ∑ j ⌊ n d ⌋ [ g c d ( i , j ) = = 1 ] i j ans=\sum_d^nf(d)\sum_i^{\lfloor \frac n d \rfloor}\sum_j^{\lfloor \frac n d \rfloor}[gcd(i,j)==1]ij ans=d∑nf(d)i∑⌊dn⌋j∑⌊dn⌋[gcd(i,j)==1]ij
设 s ( n ) = ∑ i n ∑ j n [ g c d ( i , j ) = = 1 ] i j s(n)=\sum_i^n\sum_j^{n}[gcd(i,j)==1]ij s(n)=∑in∑jn[gcd(i,j)==1]ij
根据 ∑ i n [ ( i , n ) = = 1 ] i = ϕ ( i ) 2 ∗ n \sum_i^n[(i,n)==1]i=\frac{\phi(i)}{2}*n i∑n[(i,n)==1]i=2ϕ(i)∗n
可得:
s ( n ) = ∑ i n i 2 ϕ ( i ) s(n)=\sum_i^n i^2\phi(i) s(n)=i∑ni2ϕ(i)
a n s = ∑ d n f ( d ) s ( ⌊ n d ⌋ ) ans=\sum_d^nf(d)s(\lfloor \frac n d \rfloor) ans=d∑nf(d)s(⌊dn⌋)
分块即可。
但还有一个问题, f f f是待修改的,假如树状数组求和过不去。
所以用普通分块。 O ( m l o g n ) O(mlogn) O(mlogn)
code:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const LL mod=1e9+7;
int m,n,L[2010],R[2010],cur[4000010];
int phi[4000010],pr=0,prime[4000010],h[4000010],f[4000010],sum[4000010];
int s[4000010],S[2010];
bool v[4000010];
void pre()
{
memset(v,true,sizeof(v));
phi[1]=1;
for(int i=2;i<=4000000;i++)
{
if(v[i]) prime[++pr]=i,phi[i]=i-1;
for(int j=1;j<=pr&&prime[j]*i<=4000000;j++)
{
int s=prime[j]*i;v[s]=false;
if(i%prime[j]==0) {phi[s]=phi[i]*prime[j];break;}
phi[s]=phi[i]*(prime[j]-1);
}
}
for(int i=1;i<=4000000;i++) h[i]=(h[i-1]+(LL)i*i%mod*phi[i]%mod)%mod;
for(int i=1;i<=4000000;i++) f[i]=(LL)i*i%mod,sum[i]=(sum[i-1]+f[i])%mod;
}
void change(int k,int c)
{
for(int i=k;i<=R[cur[k]];i++) (s[i]+=c)%=mod;
for(int i=cur[k];i<=cur[n];i++) (S[i]+=c)%=mod;
}
int gcd(int a,int b) {return a==0?b:gcd(b%a,a);}
int get(int k) {return (s[k]+S[cur[k]-1])%mod;}
int main()
{
pre();
scanf("%d %d",&m,&n);
int len=sqrt(n);
for(int i=1;i<=n;i++)
{
cur[i]=(i/len)+1;
if(cur[i]!=cur[i-1]) L[cur[i]]=i,R[cur[i-1]]=i-1;
}
R[cur[n]]=n;
for(int i=1;i<=n;i++)
{
s[i]=s[i-1];
if(L[cur[i]]==i) s[i]=0,S[cur[i]]=S[cur[i]-1];
s[i]=(s[i]+f[i])%mod;(S[cur[i]]+=f[i])%=mod;
}
while(m--)
{
int a,b,k;LL x;scanf("%d %d %lld %d",&a,&b,&x,&k);
int d=gcd(a,b);a/=d;b/=d;
x=x/a/b;x%=mod;change(d,-f[d]);f[d]=(int)x;change(d,f[d]);
int i=1,j=0,ans=0;
while(i<=k)
{
j=k/(k/i);
ans=(ans+(LL)h[k/i]*(get(j)-get(i-1))%mod)%mod;
i=j+1;
}
printf("%d\n",(ans+mod)%mod);
}
}