码迷,mamicode.com
首页 > 其他好文 > 详细

毒瘤之神的考验

时间:2019-05-03 16:23:04      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:应该   复杂度   递推   ret   前缀   inline   动态数组   register   while   

毒瘤之神的考验

给定n组询问,询问\(\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)mod\ 998244353,T≤10^4,n,m≤10^5\)

\(n\leq m\),显然为约数计数问题,但是式子中没有gcd,于是考虑拆\(\varphi(ij)\),它又有具体的公式,而由容斥原理我们有

\[ans=\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)=\sum_{i=1}^n\sum_{j=1}^m\frac{\varphi(i)\varphi(j)gcd(i,j)}{\varphi(gcd(i,j))}\]

所以

\[ans=\sum_{d=1}^n\frac{d}{\varphi(d)}\sum_{i=1}^n\sum_{j=1}^m\varphi(i)\varphi(j)(gcd(i,j)==d)\]

于是设

\[f(d)=\sum_{i=1}^n\sum_{j=1}^m\varphi(i)\varphi(j)(gcd(i,j)==d)\]
\[F(d)=\sum_{i=1}^n\sum_{j=1}^m\varphi(i)\varphi(j)(d|gcd(i,j))=\sum_{i=1}^{[n/d]}\sum_{j=1}^{[m/d]}\varphi(id)\varphi(jd)\]

由Mobius反演定理有

\[f(d)=\sum_{d|x}\sum_{i=1}^{[n/x]}\sum_{j=1}^{[m/x]}\varphi(ix)\varphi(jx)\mu(x/d)\]

代入有

\[ans=\sum_{x=1}^n\sum_{i=1}^{[n/x]}\varphi(ix)\sum_{j=1}^{[m/x]}\varphi(jx)\sum_{d|x}\mu(x/d)\frac{d}{\varphi(d)}\]

注意到最后面可以\(O(nlon(n))\)维护,用函数\(l\),问题在于无法解决中间的一堆\(\varphi\),现在考虑以谁为自变量维护,注意到每个固定的n/x很少,于是设\(g(x,y)=\sum_{i=1}^y\varphi(ix)\),因为sigma具有递推性,所以不难有\(g(x,y)=g(x,y-1)+\varphi(xy)\),暴力动态数组维护,时间复杂度空间复杂度也才\(nlog(n)\),现在我们所有的式子都能够维护了,考虑现在如何出解。

显然中间的式子不好维护前缀和,于是只能暴力枚举,算一下时间复杂度,也才\(10^9\),于是考虑打表分块,设

\[h(a,b,c)=\sum_{x=1}^a\sum_{i=1}^b\varphi(ix)\sum_{j=1}^c\varphi(jx)\sum_{d|x}\mu(x/d)\frac{d}{\varphi(d)}\]

由于sigma的可递推性,我们不难有

\[h(a,b,c)=h(a-1,b,c)+g(a,b)\times g(a,c)\times l(a)\]

于是我们可以先预处理一部分h,不妨把b,c限制在\(B\)里面,当b,c在所求范围,直接整除分快累加答案,这部分时间复杂度近似\(O(T\sqrt{n})\),如果\([n/x]>B\),就有\(x<[n/B]\),这部分时间复杂度应该为\(O(\frac{n}{B}T)\),所以累计起来时间复杂度应该为\(nlog(n)+nB^2+T(\frac{n}{B}+\sqrt{n})\),玄学地解决了问题,其实你也感性地理解为以一部分空间换询问的时间。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
#define con 60
#define lim 100000
#define yyb 998244353
#define swap(x,y) x^=y^=x^=y
using namespace std;
bool check[lim+1];
int prime[10000],pt,mu[lim+1],
    phi[lim+1],inv[lim+1],sxr[lim+1],
    *wch[lim+1],*czf[con+1][con+1];
il int min(int,int);
il void prepare(int),read(int&),
    pen(int);
int main(){
    int lsy,i,j,n,m,ans;
    read(lsy),prepare(lim);
    while(lsy--){
        read(n),read(m);
        if(n>m)swap(n,m);ans&=0;
        for(i=1;i<=m/con;++i)
            (ans+=(ll)wch[i][n/i]*wch[i][m/i]%yyb*sxr[i]%yyb)%=yyb;
        for(i=m/con+1;i<=n;i=j+1)
            j=min(n/(n/i),m/(m/i)),
                (ans+=(czf[n/i][m/i][j]-czf[n/i][m/i][i-1])%yyb)%=yyb;
        pen((ans+yyb)%yyb),putchar('\n');
    }
    return 0;
}
il void pen(int x){
    if(x>9)pen(x/10);putchar(x%10+48);
}
il int min(int a,int b){
    return a<b?a:b;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
il void prepare(int n){
    int i,j,k,l;
    check[1]|=mu[1]|=phi[1]|=true;
    for(i=2;i<=n;++i){
        if(!check[i])prime[++pt]=i,mu[i]=-1,phi[i]=i-1;
        for(j=1;j<=pt&&prime[j]*i<=n;++j){
            check[i*prime[j]]|=true;
            if(!(i%prime[j])){phi[i*prime[j]]=phi[i]*prime[j];break;}
            phi[i*prime[j]]=phi[i]*phi[prime[j]],mu[i*prime[j]]=~mu[i]+1;
        }
    }inv[1]|=true;
    for(i=2;i<=n;++i)inv[i]=-(ll)(yyb/i)*inv[yyb%i]%yyb;
    for(i=1;i<=n;++i)
        for(j=i;j<=n;j+=i)
            (sxr[j]+=(ll)i*inv[phi[i]]*mu[j/i]%yyb)%=yyb;
    for(i=1;i<=n;++i){
        k=n/i,wch[i]=new int[k+1];
        for(j=1,wch[i][0]&=0;j<=k;++j)
            wch[i][j]=(wch[i][j-1]+phi[i*j])%yyb;
        wch[i][0]=k;
    }
    for(j=1;j<=con;++j)
        for(k=j;k<=con;++k){
            l=n/k,czf[j][k]=new int[l+1];
            for(czf[j][k][0]&=0,i=1;i<=l;++i)
                czf[j][k][i]=(czf[j][k][i-1]+(ll)wch[i][j]*
                              wch[i][k]%yyb*sxr[i]%yyb)%yyb;
        }
}

毒瘤之神的考验

标签:应该   复杂度   递推   ret   前缀   inline   动态数组   register   while   

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10805190.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!