小Q是个程序员。
作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理。每当小Q不知道如何解决时,就只好向你求助。为了完成任务,小Q需要列一个表格,表格有无穷多行,无穷多列,行和列都从1开始标号。为了完成任务,表格里面每个格子都填了一个整数,为了方便描述,小Q把第a行第b列的整数记为f(a,b),为了完成任务,这个表格要满足一些条件:(1)对任意的正整数a,b,都要满足f(a,b)=f(b,a);(2)对任意的正整数a,b,都要满足b×f(a,a+b)=(a+b)*f(a,b)。为了完成任务,一开始表格里面的数很有规律,第a行第b列的数恰好等于a*b,显然一开始是满足上述两个条件的。为了完成任务,小Q需要不断的修改表格里面的数,每当修改了一个格子的数之后,为了让表格继续满足上述两个条件,小Q还需要把这次修改能够波及到的全部格子里都改为恰当的数。由于某种神奇的力量驱使,已经确保了每一轮修改之后所有格子里的数仍然都是整数。为了完成任务,小Q还需要随时获取前k行前k列这个有限区域内所有数的和是多少,答案可能比较大,只需要算出答案mod1,000,000,007之后的结果。
1<=m<=10000,1<=a,b,k<=N<=4*10^6,0<=x<=10^18
要想做这题,首先要知道一个很重要的结论。就是若一个格子(i,j)会被(a,b)影响到,那么当且仅当gcd(i,j)==gcd(a,b).
我们来证明一下结论。
首先根据辗转相减可以得到gcd(a,b)==gcd(a,a+b),也就是说(a,b)能更新到的所有点(i,j)必然都满足gcd(i,j)==gcd(a,b)
再根据性质二,也就是对称性,再结合性质一,可以得到b*f(a+b,a)=(a+b)*f(b,a),也就是若两个点(a,b)和(i,j)可以互相影响,则他们的f值不仅跟横坐标成正比,也跟纵坐标成正比。
那么设gcd(i,j)==d,则必然有f(i,j)=f(d,d)*i*j/d/d
由于f(a,b)的改变必然会导致f(d,d)的改变,f(d,d)的改变必然又会引起所有满足gcd(i,j)==gcd(a,b)的f(i,j)改变,于是就证明完毕了。
那么由于所有的f(a,b)都可以由f(d,d)*a*b/d/d来得到,那么我们就只用记录f(d,d)即可。去掉一维,变为f(d)
那么我们就可以开始愉快的推式子啦!!!
显然
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=4000005;
const int MOD=1000000007;
int n,m,phi[N],tot,prime[N/10],f[N],w[N],tag[N],block,val[N];
bool not_prime[N];
void prework(int n)
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i]) prime[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for (int i=1;i<=n;i++) f[i]=(f[i-1]+(LL)i*i%MOD*phi[i]%MOD)%MOD;
for (int i=1;i<=n;i++) w[i]=(w[i-1]+(LL)i*i%MOD)%MOD,val[i]=(LL)i*i%MOD;
}
int gcd(int x,int y)
{
if (!y) return x;
else return gcd(y,x%y);
}
int solve(int n)
{
int ans=0;
for (int i=1,last;i<=n;i=last+1)
{
last=n/(n/i);
ans=(ans+(LL)(w[last]+tag[(last+block-1)/block]-w[i-1]-tag[(i+block-2)/block])*f[n/i]%MOD)%MOD;
}
return (ans+MOD)%MOD;
}
int main()
{
scanf("%d%d",&m,&n);
block=sqrt(n);
prework(n);
while (m--)
{
int a,b,y;LL x;
scanf("%d%d%lld%d",&a,&b,&x,&y);
int c=gcd(a,b),v=(LL)x/(a/c)/(b/c)%MOD,u=val[c];val[c]=v;
for (int i=c;i<=(c+block-1)/block*block;i++) w[i]=(w[i]+v-u)%MOD,w[i]=(w[i]+MOD)%MOD;
for (int i=(c+block-1)/block+1;i<=(n+block-1)/block;i++) tag[i]=(tag[i]+v-u)%MOD,tag[i]=(tag[i]+MOD)%MOD;
printf("%d\n",solve(y));
}
}