P7504 「HMOI R1」可爱的德丽莎

好像被我推复杂了...

简述题意

求:

\[\sum^{n}_{x=1}\sum^{n}_{y=1}\sum^{x}_{i=1}i[(x,k_{1})=1][(i,x)=1]\sum^{y}_{j=1}[(y,k_{2})=1][(y,j)=1]j \]

\(n,k_1,k_2\leq 2\times 10^9\)。

Solution

首先是推式子:

\[\begin{aligned} ans&=\sum^{n}_{x=1}\sum^{x}_{i=1}i[(x,k_{1})=1][(i,x)=1]\sum^{n}_{y=1}\sum^{y}_{j=1}[(y,k_{2})=1][(y,j)=1]j\\ \end{aligned} \]

注意到左右两边形式一样,设 \(S(n,k)=\sum^{n}_{x=1}\sum^{x}_{i=1}i[(x,k)=1][(i,x)=1]\)。

那么有:

\[\begin{aligned} ans&=S(n,k_{1})\times S(n,k_{2})\\ \\ S(n,k)&=\sum^{n}_{x=1}\sum^{x}_{i=1}i[(x,k)=1][(i,x)=1]\\ &=\sum^{n}_{x=1}[(x,k)=1]\sum^{x}_{i=1}i\sum_{g|\gcd(i,x)}\mu(g)\\ &=\sum^{n}_{x=1}[(x,k)=1]\sum^{}_{g|x}\mu(g)g C_{2}(\frac{x}{g})\\ &=\sum^{n}_{x=1}\sum_{t|\gcd(x,k_1)}\mu(t)\sum^{}_{g|x}\mu(g)g C_{2}(\frac{x}{g})\\ &=\frac{1}{2}\sum^{}_{t|k_{1}}\mu(t)\sum^{\lfloor\frac{n}{t}\rfloor}_{x=1}x\sum^{}_{g|x}\mu(g)\frac{x}{g}+\mu(g)\\ &=\frac{1}{2}\sum^{}_{t|k_{1}}\mu(t)\sum^{\lfloor\frac{n}{t}\rfloor}_{x=1}x\varphi(x)+[x=1]\\ &=1+\frac{1}{2}\sum^{}_{t|k_{1}}\mu(t)\sum^{\lfloor\frac{n}{t}\rfloor}_{x=1}tx\varphi(tx))\\ \end{aligned} \]

如果是求 \(i\varphi(i)\) 的前缀和,可以直接上 Min_25 ,可是这里的形式比较诡异,不能直接求。

不过注意到 \(\mu(t)\not = 0\),当且仅当 \(t\) 中的每一个质因子只出现一次,似乎是可以做一个DP。

我们令 \(p\) 表示 \(t\) 中的某一个质因子,同时定义一个新的函数 \(G(n,t)\)。

\[\begin{aligned} G(n,t)&=\sum^{n}_{x=1}x\varphi(tx)\\ &=\sum^{n}_{x=1}[\gcd(x,p)=1]x\varphi(x\frac{t}{p})(p-1)+\sum^{\lfloor\frac{n}{p}\rfloor}_{x=1}xp^2\varphi(xp\frac{t}{p})\\ &=\sum^{n}_{x=1}x\varphi(x\frac{t}{p})(p-1)+\sum^{\lfloor\frac{n}{p}\rfloor}_{x=1}xp\varphi(xt)\\ &=(p-1)G(n,\frac{t}{p})+pG(\lfloor\frac{n}{p}\rfloor,t)\\ \\ G(n,1)&=\sum^{n}_{i=1}i\varphi(i)=F(n)\\ \\ S(n,k)&=1+\frac{1}{2}\sum_{t|k \And \mu(t)\not = 0}t\mu(t)G(\lfloor \frac{n}{t} \rfloor,t) \end{aligned} \]

加上记忆化之后,复杂度便正确了。

首先是 \(G\) 部分,总共状态个数是 \(O(k^{\frac{1}{3}}n^{\frac{1}{2}})\) 的,每次转移是 \(O(1)\)。

然后是 \(F\) 部分,只有 \(O(\sqrt{n})\) 个取值,只需要在 Min_25 内加一个记忆化也是可以做到 $O(n^{\frac{3}{4}}) $ 或者 \(O(\frac{n^{\frac{3}{4}}}{\ln n})\) 。

视 \(n,k\) 同阶,那么总复杂度为 \(O(n^{\frac{5}{6}})\) ,实测跑的还是比较快的,完全跑不满,瓶颈反而在 Min_25 内记忆化所使用的 map 中。

Code

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<unordered_map>
using namespace std;
#define ll long long 
#define ri int
#define pii pair<int,int>
const ll mod=998244353,inv=mod+1>>1,inv3=332748118;
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 MAXN=1e5+7;
int totcnt=0;
namespace Getphi{
    const int MAXM=1e7+7;
    int val[MAXM],as[MAXM],nxt[MAXM],mapcnt;
    struct hmap{
        static const int P=10007;
        int hed[P];
        bool count(int x){
            int c=hed[x%P];
            while(c){
                if(val[c]==x) return 1;
                c=nxt[c];
            }return 0;
        }
        int& operator [](int x){
            int c=hed[x%P];
            while(c){
                if(val[c]==x) return as[c];
                c=nxt[c];
            }
            ++mapcnt;val[mapcnt]=x;nxt[mapcnt]=hed[x%P];hed[x%P]=mapcnt;
            return as[mapcnt];
        }
        int size(){return mapcnt;}
    }S[4650];
    int n,p1[MAXN],p2[MAXN],cnt,N,flag[MAXN],prim[MAXN],w[MAXN];
    int pos(int x){
        if(1ll*x*x<=n) return p1[x];
        else return p2[n/x];
    }
    ll g1[MAXN],g2[MAXN];
    ll C2(ll x){return x*(x+1)/2%mod;}
    ll C3(ll x){return C2(x)*(x+x+1)%mod*inv3%mod;}
    void init(int _n){
        n=_n;
        N=sqrt(n);
        for(ri i=2;i<=N;++i){
            if(!flag[i]) prim[++prim[0]]=i;
            for(ri j=1;j<=prim[0]&&i*prim[j]<=N;++j){
                flag[i*prim[j]]=1;
                if(i%prim[j]==0) break;
            }
        }
        for(ri l=1,r;l<=n;l=r+1){
            int cur=n/l;r=n/cur;
            w[++cnt]=cur;
            if(1ll*cur*cur<=n) p1[cur]=cnt;
            else p2[n/cur]=cnt;
            g1[cnt]=C2(cur)-1;
            g2[cnt]=C3(cur)-1;
        }
        for(ri t=1;t<=prim[0];++t){
            for(ri i=1;i<=cnt&&w[i]>=prim[t]*prim[t];++i){
                int nxtl=pos(w[i]/prim[t]),nxtr=(t==1?0:pos(prim[t-1]));
                g1[i]=dec(g1[i],dec(g1[nxtl],g1[nxtr])*prim[t]%mod);
                g2[i]=dec(g2[i],dec(g2[nxtl],g2[nxtr])*prim[t]%mod*prim[t]%mod);
            }
        }
    }
    ll getS(int n,int cur){
        int P=pos(n);
        if(cur&&prim[cur]>=n) return 0;
        if(S[cur].count(P)) return S[cur][P];
        int r=pos(n),l=cur==0?0:pos(prim[cur]);
        ll ans=dec(dec(g2[r],g2[l]),dec(g1[r],g1[l]));
        for(ri i=cur+1;i<=prim[0]&&1ll*prim[i]*prim[i]<=n;++i){
            for(ll e=1,v=prim[i],W=1;v<=n;++e,v*=prim[i],W*=prim[i]){
                ll res=getS(n/v,i);
                if(e!=1) ++res;
                res=res*v%mod*W%mod*(prim[i]-1)%mod;
                ans=add(ans,res);
            }
        }
        return S[cur][P]=ans;
    }
    ll getphi(ll x){
        ll now=getS(x,0)+1;
        return now;
    }
}
ll ans;
ll sta[64],top;
int f[64][MAXN];
ll g(ll n,int cur){
    if(n==0) return 0;
    int P=Getphi::pos(n);
    if(~f[cur][P]) return f[cur][P];
    if(cur==0) return f[cur][P]=Getphi::getphi(n);
    return f[cur][P]=add((sta[cur]-1)*g(n,cur-1)%mod,sta[cur]*g(n/sta[cur],cur)%mod);
}
ll S(ll n,ll k){
    ll res=1;
    for(ri t=1;t*t<=k;++t){
        if(k%t) continue;
        if(t<=n){
            ll x=t;
            int now=1;
            top=0;
            for(ll i=2;i*i<=t&&i<=x;++i){
                int cnt=0;
                while(x%i==0) ++cnt,x/=i;
                if(cnt>1) goto Nex;
                if(cnt) sta[++top]=i,now=-now;
            }
            if(x>1) now=-now,sta[++top]=x;
            for(ri i=0;i<=top;++i) for(ri j=0;j<=Getphi::cnt;++j) f[i][j]=-1;
            if(now== 1) res=add(res,g(n/t,top)*t%mod);
            if(now==-1) res=dec(res,g(n/t,top)*t%mod);
            Nex:;
        }
        if(t*t!=k&&k/t<=n){
            ll x=(k/t);
            int now=1;
            top=0;
            for(ll i=2;i*i<=(k/t)&&i<=x;++i){
                int cnt=0;
                while(x%i==0) ++cnt,x/=i;
                if(cnt>1) goto Next;
                if(cnt) sta[++top]=i,now=-now;
            }
            if(x>1) now=-now,sta[++top]=x;
            for(ri i=0;i<=top;++i) for(ri j=0;j<=Getphi::cnt;++j) f[i][j]=-1;
            if(now== 1) res=add(res,g(n/(k/t),top)*(k/t)%mod);
            if(now==-1) res=dec(res,g(n/(k/t),top)*(k/t)%mod);
            Next:;
        }
    }
    return res*inv%mod;
}
ll n,k1,k2;
int main(){
    // freopen("rand.in","r",stdin);
    // freopen("1.out","w",stdout);
    scanf("%lld%lld%lld",&n,&k1,&k2);
    Getphi::init(n);
    printf("%lld\n",S(n,k1)*S(n,k2)%mod);
}
上一篇:最小生成树算法Kruskal和prim


下一篇:PS超快速制作护肤品倒影教程