• [SDOI2017]数字表格


    [SDOI2017]数字表格

    (f)为fbi数,即(f[0]=0,f[1]=1,f[i]=f[i-1]+f[i-2]),现在给出T组询问,询问(prod_{i=1}^nprod_{j=1}^mf(gcd(i,j)),T≤1000,1≤n,m≤10^6)

    通常我们所做的约数计数问题都是与累加有关,而此处与累乘有关,所以最自然的想法,要么是类比,要么必然转为累加,设(nleq m),所以

    [ans=prod_{i=1}^nprod_{j=1}^mf(gcd(i,j))=prod_{d=1}^nprod_{i=1}^nprod_{j=1}^mf(d)(gcd(i,j)==d) ]

    (注:其实这样的表达不够严谨,因为当不满足条件,对应的值为0,所以含义不应该是简单的相乘,应该是(gcd(i,j)==d?f(d):1))

    [=prod_{d=1}^nf(d)^{sum_{i=1}^nsum_{j=1}^m(gcd(i,j)==d)} ]

    于是设

    [f(d)=sum_{i=1}^nsum_{j=1}^m(gcd(i,j)==d) ]

    [F(d)=[n/d][m/d] ]

    由Mobius反演定理有

    [f(d)=sum_{d|x}[n/x][m/x]mu(x/d) ]

    代入即

    [ans=prod_{d=1}^nf(d)^{sum_{d|x}[n/x][m/x]mu(x/d)}= ]

    [prod_{d=1}^nprod_{d|x}f(d)^{[n/x][m/x]mu(x/d)}= ]

    [prod_{d=1}^nprod_{d|x}f(d)^{[n/x][m/x]mu(x/d)} ]

    [prod_{x=1}^n(prod_{d|x}f(d)^{mu(x/d)})^{[n/x][m/x]} ]

    显然里面可以维护,采取倍数型维护方式即可,而对于次方自然可以整除分块,时间复杂度应为(O(nlog(n)+Tsqrt{n}log(n)))

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define il inline
    #define ri register
    #define ll long long
    #define lim 1000000
    #define yyb 1000000007
    #define swap(x,y) x^=y^=x^=y
    using namespace std;
    bool check[lim+1];
    int mu[lim+1],prime[100000],pt;
    ll f[lim+1],pf[lim+1],pfi[lim+1],ans;
    il ll pow(ll,ll);
    il void prepare(int);
    template<class free>il free Min(free,free);
    int main(){
        int sxr,n,m,i,j;
        scanf("%d",&sxr),prepare(lim);
        while(sxr--){
            scanf("%d%d",&n,&m);
            if(n>m)swap(n,m);ans=1;
            for(i=1;i<=n;i=j+1)
                j=Min(n/(n/i),m/(m/i)),
                    (ans*=pow(pf[j]*pfi[i-1]%yyb,(ll)(n/i)*(m/i)))%=yyb;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    template<class free>
    il free Min(free a,free b){
        return a<b?a:b;
    }
    il ll pow(ll x,ll y){
        ll ans(1);while(y){
            if(y&1)(ans*=x)%=yyb;
            (x*=x)%=yyb,y>>=1;
        }return ans;
    }
    il void prepare(int n){
        mu[1]|=check[1]|=true;
        f[1]|=pf[0]|=pf[1]|=pfi[0]|=true;
        int i,j;
        for(i=2;i<=n;++i){
            if(!check[i])prime[++pt]=i,mu[i]=-1;
            for(j=1;j<=pt&&prime[j]*i<=n;++j){
                check[i*prime[j]]|=true;
                if(!(i%prime[j]))break;
                mu[i*prime[j]]=~mu[i]+1;
            }f[i]=(f[i-1]+f[i-2])%yyb,pf[i]=pf[i-1]*f[i]%yyb;
        }pfi[n]=pow(pf[n],yyb-2);
        for(i=n;i>1;--i)
            pfi[i-1]=pfi[i]*f[i]%yyb;
        for(i=0;i<=n;++i)f[i]=1;
        for(i=1;i<=n;++i)
            for(j=i;j<=n;j+=i)
                if(mu[j/i]==1)(f[j]*=pf[i]*pfi[i-1]%yyb)%=yyb;
                else if(mu[j/i]==-1)(f[j]*=pfi[i]*pf[i-1]%yyb)%=yyb;
        for(i=1;i<=n;++i)pf[i]=f[i]*pf[i-1]%yyb;pfi[n]=pow(pf[n],yyb-2);
        for(i=n;i>1;--i)pfi[i-1]=pfi[i]*f[i]%yyb;
    }
    
    
  • 相关阅读:
    继承
    反射
    DOS使用笔记
    [LeetCode] Merge Intervals
    [LeetCode] Insert Interval
    [LeetCode] Permutation Sequence
    [LeetCode] Rotate List
    [LeetCode] Text Justification
    [LeetCode] Simplify Path(可以不用看)
    [LeetCode] Edit Distance(很好的DP)
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10799829.html
Copyright © 2020-2023  润新知