LOJ#3020. 「CQOI2017」小 Q 的表格

首先要清楚这道题的修改是啥意思。

题目里给的限制都特别像辗转相减,于是可以往这个方向靠。

不难发现,对于任意的 \(f(a,b),f(c,d)\),如果有 \(\gcd(a,b)=\gcd(c,d)\) ,那么 \(\frac{f(a,b)}{ab}=\frac{f(c,d)}{cd}\),也就是说 \(f(a,b)=x -> f(c,d)=cd\frac{x}{ab}\)

可以设一个函数 \(g(x)\) 表示所有的满足 \(\gcd(a,b)=g\)\(f(a,b)=abg(x)\)

此时可以列出式子:

\[\begin{aligned} ans&=\sum^{k}_{d=1}d^2g(d)\sum^{\lfloor\frac{k}{d}\rfloor}_{i=1}\sum^{\lfloor\frac{k}{d}\rfloor}_{j=1}[\gcd(i,j)=1]ij\\ &=\sum^{k}_{T=1}\binom{\lfloor\frac{k}{T}\rfloor}{2}^2\sum_{d|T}d^2g(d)\mu(\frac{T}{d})\\ \end{aligned} \]

如果你得到了上面这个式子并尝试化简,那么恭喜你,你掉进坑列了

或许有一些大佬真的可以优化到可以接受的复杂度,但是我的水平最多只能优化到 \(O(mk^{\frac{3}{4}})\) ,是过不了的。

实际上,这个式子的正确方向应该是这样的:

\[\begin{aligned} ans&=\sum^{k}_{d=1}d^2g(d)\sum^{\lfloor\frac{k}{d}\rfloor}_{i=1}\sum^{\lfloor\frac{k}{d}\rfloor}_{j=1}[\gcd(i,j)=1]ij\\ &=\sum^{k}_{d=1}g(d)(-1+2\sum^{\lfloor\frac{k}{d}\rfloor}_{i=1}i\sum^{i}_{j=1}[\gcd(i,j)=1]j)\\ \end{aligned} \]

因为 \((a,b) = (a,a-b)\) ,所以所有和 \(i\) 互质的数可以分成 \(\frac{\varphi(i)}{2}\) 组,每组的和为 \(a\)

于是有 \(\sum^{i}_{j=1}[\gcd(i,j)=1]=\frac{i\varphi(i)}{2}\) ,同时 \(i=1\) 的时候要特判。

回到前面那个式子,因为外面有个 \(\times 2\),并且把这个 \(2\) 抵消之后刚好把 \(1\) 的特判给去掉了,可以进一步优化到:

\[\begin{aligned} ans&=\sum^{k}_{d=1}d^2g(d)\sum^{\lfloor\frac{k}{d}\rfloor}_{i=1}i^2\varphi(i)\\ \end{aligned} \]

后面那东西可以提前预处理,直接用数论分块做,同时用分块维护单点修改区间查询,可以做到 \(O(m\sqrt{n})\) 的复杂度。

code
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cassert>
using namespace std;
#define ll long long 
#define ri int
#define pii pair<int,int>
const ll mod=1e9+7;
ll add(ll x,ll y){return (x+=y)<mod?x:x-mod;}
ll dec(ll x,ll y){return (x-=y)<0?x+mod:x;}
ll ksm(ll d,ll t,ll res=1){for(;t;t>>=1,d=d*d%mod) if(t&1) res=res*d%mod;return res;}
const int B=2048;
const int MAXN=4e6+10*B+1;
int n,m,phi[MAXN],prim[MAXN],sum[MAXN],flag[MAXN],f[MAXN];
void sieve(){
    phi[1]=1;
    for(ri i=2;i<=n;++i){
        if(!flag[i]) prim[++prim[0]]=i,phi[i]=i-1;
        for(ri j=1;j<=prim[0]&&i*prim[j]<=n;++j){
            flag[i*prim[j]]=1;
            if(i%prim[j]==0){
                phi[i*prim[j]]=phi[i]*prim[j];
                break;
            }
            phi[i*prim[j]]=phi[i]*(prim[j]-1);
        }
    }
}
struct Block{
    int rsum[MAXN/B+10],bsum[MAXN];
    void insert(int x,int w){
        int l=x/B*B,r=l+B-1;
        for(ri i=x;i<=r;++i) bsum[i]=add(bsum[i],w);
        for(ri i=x/B;i<=n/B;++i) rsum[i]=add(rsum[i],w);
    }
    int ask(int x){
        // int tot=0;
        // for(ri i=1;i<=x;++i) tot=add(tot,1ll*f[i]*i*i%mod);
        if(x/B){
            // assert(tot==add(bsum[x],rsum[x/B-1]));
            return add(bsum[x],rsum[x/B-1]);
        }
        else{
            // assert(tot==bsum[x]);
            return bsum[x];
        }
    }
    int query(int l,int r){return dec(ask(r),ask(l-1));}
    void init(){
        for(ri i=1;i<=n;++i) bsum[i]=1ll*i*i%mod,rsum[i/B]=add(rsum[i/B],1ll*i*i%mod);
        for(ri i=0;i<=n/B;++i){
            int l=i*B,r=l+B-1;
            for(ri j=l+1;j<=r;++j) bsum[j]=add(bsum[j-1],bsum[j]);
            if(i) rsum[i]=add(rsum[i],rsum[i-1]);
        }
    }
}T;
int gcd(int x,int y){for(;y;x%=y,swap(x,y));return x;}
int main(){
    // freopen("rand.in","r",stdin);
    // freopen("1.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>m>>n;sieve();
    for(ri i=1;i<=n;++i) sum[i]=add(sum[i-1],1ll*i*i%mod*phi[i]%mod),f[i]=1;T.init();
    // for(ri i=1;i<=n;++i) printf("%d ",phi[i]);puts("");
    while(m--){
        int x,y,k,g;ll w,d;
        cin>>x>>y>>w>>k;
        g=gcd(x,y);
        d=dec(w%mod*ksm(1ll*x*y%mod,mod-2)%mod,f[g]);
        f[g]=add(f[g],d);
        T.insert(g,d*g%mod*g%mod);
        int ans=0;
        for(ri l=1,r;l<=k;l=r+1){
            r=k/(k/l);
            // printf("[%d %d %d]\n",l,r,T.query(l,r));
            ans=add(ans,1ll*T.query(l,r)*sum[k/l]%mod);
        }
        cout<<ans<<endl;
    }
}
posted @ 2022-02-19 09:58  krimson  阅读(36)  评论(0编辑  收藏  举报