正题
题目链接:https://www.luogu.com.cn/problem/P3700
题目大意
一个n∗nn*nn∗n个数的数字表格,开始位置(a,b)(a,b)(a,b)上的是a∗ba*ba∗b。数字表格需满足以下条件
- 对于任意(a,b)(a,b)(a,b)有f(a,b)=f(b,a)f(a,b)=f(b,a)f(a,b)=f(b,a)
- 对于任意(a,b)(a,b)(a,b)有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)
mmm次修改数字表格中的一个数,你需要调整其他数字使其满足条件,然后求前kkk行前kkk列的数字和。
解题思路
一道神仙题,首先我们拿出这个不伦不类的式子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)化成
f(a,a+b)a(a+b)=f(a,b)ab\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)ab=f(gcd(a,b),gcd(a,b))gcd(a,b)2\frac{f(a,b)}{ab}=\frac{f(gcd(a,b),gcd(a,b))}{gcd(a,b)^2}abf(a,b)=gcd(a,b)2f(gcd(a,b),gcd(a,b))
定义d=gcd(a,b)d=gcd(a,b)d=gcd(a,b),也就是f(a,b)=f(d,d)abgcd(a,b)2f(a,b)=\frac{f(d,d)ab}{gcd(a,b)^2}f(a,b)=gcd(a,b)2f(d,d)ab
那么k∗kk*kk∗k的数字和就是∑i=1kfi,i∑x=1k∑y=1kxyi2[gcd(x,y)==i]\sum_{i=1}^kf_{i,i}\sum_{x=1}^k\sum_{y=1}^k\frac{xy}{i^2}[gcd(x,y)==i]i=1∑kfi,ix=1∑ky=1∑ki2xy[gcd(x,y)==i]
然后化成∑i=1kfi,i∑x=1⌊ki⌋∑y=1⌊ki⌋xy[gcd(x,y)==1]\sum_{i=1}^kf_{i,i}\sum_{x=1}^{\lfloor\frac{k}{i}\rfloor}\sum_{y=1}^{\lfloor\frac{k}{i}\rfloor}xy[gcd(x,y)==1]i=1∑kfi,ix=1∑⌊ik⌋y=1∑⌊ik⌋xy[gcd(x,y)==1]
之后我们有结论是后面那个东西∑x=1n∑y=1nxy[gcd(x,y)==1]=∑i=1nφ(i)i2\sum_{x=1}^{n}\sum_{y=1}^{n}xy[gcd(x,y)==1]=\sum_{i=1}^n\varphi(i)i^2∑x=1n∑y=1nxy[gcd(x,y)==1]=∑i=1nφ(i)i2
具体证明的话就是
令H(x)=∑x=1n∑y=1nxy[gcd(x,y)==1]H(x)=\sum_{x=1}^{n}\sum_{y=1}^{n}xy[gcd(x,y)==1]H(x)=∑x=1n∑y=1nxy[gcd(x,y)==1]
那么H(x)H(x)H(x)比H(x−1)H(x-1)H(x−1)多了一个2x∑y=1n[gcd(x,y)==1]y2x\sum_{y=1}^n[gcd(x,y)==1]y2x∑y=1n[gcd(x,y)==1]y
也就是多了一个x∗2∗φ(x)x2x*2*\frac{\varphi(x)x}{2}x∗2∗2φ(x)x
所以可以线性预处理这个东西
我们就可以对后面那个东西做整除分块,我们就需要处理fi,if_{i,i}fi,i的前缀和
我们一次操作需要进行n\sqrt nn次询问前缀和,但是修改只需要一次,所以我们可以平衡一下时间。也就是降低询问复杂度提升修改复杂度,用分块存储块中每个位置的块内前缀和和块的前缀和即可。
时间复杂度O(mn)O(m\sqrt n)O(mn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const ll N=4e6+10,P=1e9+7;
ll n,m,T,w[N],v[N],sum[N],L[N],R[N];
ll cnt,pri[N],phi[N],g[N],pos[N];
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans;
}
void Prime(){phi[1]=1;for(ll i=2;i<=n;i++){if(!v[i])pri[++cnt]=i,phi[i]=i-1;for(ll j=1;j<=cnt&&i*pri[j]<=n;j++){v[i*pri[j]]=1;if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}phi[i*pri[j]]=phi[i]*phi[pri[j]];}}for(ll i=1;i<=n;i++)g[i]=(g[i-1]+phi[i]*i%P*i%P)%P;return;
}
ll GetS(ll x){if(!x)return 0ll;return (sum[pos[x]-1]+w[x])%P;
}
int main()
{scanf("%lld%lld",&m,&n);Prime();T=sqrt(n);for(ll i=1;i<=n;i++)v[i]=i*i%P;for(ll i=1;i<=T;i++)L[i]=R[i-1]+1,R[i]=i*T;if(T*T!=n)T++,L[T]=R[T-1]+1,R[T]=n;for(ll i=1;i<=T;i++){for(ll j=L[i];j<=R[i];j++)pos[j]=i,w[j]=(v[j]+w[j-1]*(j>L[i]))%P;sum[i]=(sum[i-1]+w[R[i]])%P;}while(m--){ll a,b,x,k;scanf("%lld%lld%lld%lld",&a,&b,&x,&k);x%=P;ll d=__gcd(a,b),y=pos[d];v[d]=x*d*d%P*power(a*b%P,P-2)%P;for(ll i=d;i<=R[y];i++)w[i]=((i>L[y])*w[i-1]+v[i])%P;for(ll i=y;i<=T;i++)sum[i]=(sum[i-1]+w[R[i]])%P;ll ans=0;for(ll l=1,r;l<=k;l=r+1){r=k/(k/l);ans=(ans+g[k/l]*(GetS(r)-GetS(l-1)+P)%P)%P;}printf("%lld\n",ans);}return 0;
}