P3700-[CQOI2017]小Q的表格【分块,欧拉函数】
正題
題目鏈接:https://www.luogu.com.cn/problem/P3700
題目大意
一個n?nn*nn?n個數的數字表格,開始位置(a,b)(a,b)(a,b)上的是a?ba*ba?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∑k?fi,i?x=1∑k?y=1∑k?i2xy?[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∑k?fi,i?x=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=1n?xy[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=1n?xy[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; }總結
以上是生活随笔為你收集整理的P3700-[CQOI2017]小Q的表格【分块,欧拉函数】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【IT之家开箱】iGame GeForc
- 下一篇: 罕见,“超低温”褐矮星发射无线电波