根据辗转相减可以知道,相互影响的就是
gcd
相同的那些数。又根据条件
2
可以知道,所有
接下来考虑询问,也就是求
====∑i=1n∑j=1nf(gcd(i,j))∗ij∑d=1nf(d)∑i=1n∑j=1nij∗[gcd(i,j)=d]∑d=1nf(d)∗d2∑i=1⌊nd⌋∑j=1⌊nd⌋ij∗e(gcd(i,j))∑d=1nf(d)∗d2∑i=1⌊nd⌋∑j=1⌊nd⌋ij∑x|i,x|jμ(x)∑d=1nf(d)∗d2∑x=1⌊nd⌋μ(x)x2∑i=1⌊ndx⌋∑j=1⌊ndx⌋ij
记
s(n)=∑i=1ni=n(n+1)2
g(n)=∑i=1nμ(i)∗i2∗s2(⌊ni⌋)
如果能够预处理出 g ,就可以下底函数分块来求解原问题。但是如果直接依次求是
g(n)=g(n−1)+∑i|nμ(i)∗i2(s2(ni)−s2(ni−1))=g(n−1)+n3∑i|nμ(i)∗1i
其中 h(n)=∑i|nμ(i)∗1i 为积性函数可以线性筛,于是我们就可以 O(n) 预处理出 g 。
还有一个问题,在对答案进行下底函数分块的时候需要维护
好像有一点卡常,考虑到比较小的 d=gcd(x,y) 被调用的次数比较多,可以在分块的时候维护后缀和,这样修改次数可以减少。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
const int p=1000000007,maxn=4000010,maxT=2010;
LL f[maxn],g[maxn],h[maxn],inv[maxn],
sum[maxT],sumin[maxT][maxT];
int prm[maxn],have[maxn],bel[maxn],L[maxT],R[maxT],
q,n,T,tot;
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
void pause()
{
int x;
x=1;
}
void init()
{
inv[1]=g[1]=h[1]=1;
for (int i=2;i<=n;i++)
{
inv[i]=(p-inv[p%i])*(p/i)%p;
if (!have[i])
{
prm[++tot]=i;
h[i]=(1-inv[i]+p)%p;
}
for (int j=1;j<=tot&&(LL)i*prm[j]<=n;j++)
{
have[i*prm[j]]=1;
if (i%prm[j]==0)
{
h[i*prm[j]]=h[i];
break;
}
else h[i*prm[j]]=h[i]*h[prm[j]]%p;
}
g[i]=(g[i-1]+(LL)i*i%p*i%p*h[i])%p;
}
T=sqrt(n);
for (int i=1;i<=T;i++)
{
L[i]=R[i-1]+1;
R[i]=i==T?n:L[i]+T-1;
for (int j=L[i];j<=R[i];j++)
{
f[j]=1;
bel[j]=i;
sumin[i][j-L[i]+1]=(sumin[i][j-L[i]]+(LL)j*j)%p;
}
}
for (int i=T;i;i--)
sum[i]=(sum[i+1]+sumin[i][R[i]-L[i]+1])%p;
}
LL getsum(int l,int r)
{
//if (l==10&&r==13) pause();
//LL ret1;
int x=bel[l],y=bel[r];
if (x==y) return (sumin[x][r-L[x]+1]-sumin[x][l-L[x]]+p)%p;
return (sum[x+1]-sum[y]+p+sumin[y][r-L[y]+1]+sumin[x][R[x]-L[x]+1]-sumin[x][l-L[x]]+p)%p;
/*LL ret=0;
for (int i=l;i<=r;i++) ret=(ret+f[i]*i%p*i%p)%p;
if (ret!=ret1) pause();
return ret;*/
}
void update(int d)
{
for (int j=d;j<=R[bel[d]];j++)
sumin[bel[d]][j-L[bel[d]]+1]=(sumin[bel[d]][j-L[bel[d]]]+f[j]*j%p*j)%p;
for (int j=bel[d];j;j--)
sum[j]=(sum[j+1]+sumin[j][R[j]-L[j]+1])%p;
}
void solve(int m)
{
LL ans=0;
int u;
for (int j=1;j<=m;j=u+1)
{
u=m/(m/j);
ans=(ans+getsum(j,u)*g[m/j])%p;
}
printf("%lld\n",ans);
}
int main()
{
/*freopen("table.in","r",stdin);
freopen("table.out","w",stdout);*/
int xx,yy,m,d;
LL x;
scanf("%d%d",&q,&n);
init();
while (q--)
{
scanf("%d%d%lld%d",&xx,&yy,&x,&m);
x%=p;
d=gcd(xx,yy);
f[d]=(LL)x*inv[xx]%p*inv[yy]%p;
update(d);
solve(m);
}
}