[SDOI2017]数字表格

[SDOI2017]数字表格

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

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

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

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

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

于是设

\[f(d)=\sum_{i=1}^n\sum_{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}^n\prod_{d|x}f(d)^{[n/x][m/x]\mu(x/d)}= \]

\[\prod_{d=1}^n\prod_{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)+T\sqrt{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\n",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;
}

posted @ 2019-05-01 14:44  a1b3c7d9  阅读(154)  评论(0编辑  收藏  举报