【[SDOI2017]数字表格】

\[Ans=\prod_{i=1}^N\prod_{j=1}^MFib[(i,j)]\]

连乘的反演,其实并没有什么不一样

我们把套路柿子拿出来

\[F(n)=\sum_{i=1}^N\sum_{j=1}^M[n|(i,j)]=\left \lfloor \frac{N}{n} \right \rfloor\times \left \lfloor \frac{M}{n} \right \rfloor=\sum_{n|d}f(d)\]

\[f(n)=\sum_{i=1}^N\sum_{j=1}^M[n=(i,j)]=\sum_{n|d}\mu(\frac{d}{n})\left \lfloor \frac{N}{d} \right \rfloor \left \lfloor \frac{M}{d} \right \rfloor\]

我们要求的就是

\[Ans=\prod_{i=1}^NFib(i)^{f(i)}\]

把它化开

\[Ans=\prod_{i=1}^NFib(i)^{\sum_{i|d}\mu(\frac{d}{i})\left \lfloor \frac{N}{d} \right \rfloor \left \lfloor \frac{M}{d} \right \rfloor}\]

非常显然的就是

\[Ans=\prod_{d=1}^N(\prod_{i|d}Fib(i)^{\mu(\frac{d}{i})})^{\left \lfloor \frac{N}{d} \right \rfloor \left \lfloor \frac{M}{d} \right \rfloor}\]

利用调和级数在\(O(nlogn)\)的时间内处理出\(\prod_{i|d}Fib(i)^{\mu(\frac{d}{i})}\)的值,做一个前缀积就好了,之后整除分块和快速幂一起上就好了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define maxn 1000005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const LL mod=1e9+7;
inline int read()
{
    char c=getchar();int x=0;
    while(c<‘0‘||c>‘9‘) c=getchar();
    while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
LL fib[maxn],pre[maxn];
int T,N[1005],M[1005],U;
int f[maxn],p[maxn],mu[maxn];
LL exgcd(LL a,LL b,LL &x,LL &y) {if(!b) return x=1,y=0,a;LL r=exgcd(b,a%b,y,x);y-=a/b*x;return r;}
inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1ll) S=S*a%mod;b>>=1ll;a=a*a%mod;} return S;}
inline LL inv(LL a){LL x,y;LL r=exgcd(a,mod,x,y);return (x%mod+mod)%mod;}
inline LL solve(LL a,int b) {if(!b) return 1;if(b==1) return a;if(b==-1) return inv(a);}
int main()
{
    T=read();
    for(re int i=1;i<=T;i++) N[i]=read(),M[i]=read();
    for(re int i=1;i<=T;i++) if(N[i]>M[i]) std::swap(N[i],M[i]);
    for(re int i=1;i<=T;i++) U=max(U,N[i]);
    mu[1]=1,f[1]=1,pre[1]=1,pre[0]=1;
    for(re int i=2;i<=U;i++)
    {
        pre[i]=1;
        if(!f[i]) p[++p[0]]=i,mu[i]=-1;
        for(re int j=1;j<=p[0]&&p[j]*i<=U;j++) {f[p[j]*i]=1;if(i%p[j]==0) break;mu[p[j]*i]=-1*mu[i];}
    }
    fib[1]=fib[2]=1;
    for(re int i=3;i<=U;i++) fib[i]=fib[i-1]+fib[i-2],fib[i]%=mod;
    for(re int i=1;i<=U;i++)
        for(re int j=1;j*i<=U;j++) pre[i*j]*=solve(fib[i],mu[j]),pre[i*j]%=mod;
    for(re int i=1;i<=U;i++) pre[i]*=pre[i-1],pre[i]%=mod;
    for(re int t=1;t<=T;t++)
    {
        int n=N[t],m=M[t];
        LL ans=1;
        for(re LL l=1,r;l<=n;l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            ans*=quick(pre[r]*inv(pre[l-1])%mod,(n/l)*(m/l)%(mod-1));ans%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10205617.html

时间: 2024-10-03 22:56:55

【[SDOI2017]数字表格】的相关文章

[Sdoi2017]数字表格

[Sdoi2017]数字表格 http://www.lydsy.com/JudgeOnline/problem.php?id=4816 Time Limit: 50 Sec  Memory Limit: 128 MB Description Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)],其

【BZOJ4816】[Sdoi2017]数字表格 莫比乌斯反演

[BZOJ4816][Sdoi2017]数字表格 Description Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)],其中gcd(i,j)表示i,j的最大公约数.Doris的表格中共有n×m个数,她想知道这些数的乘积是多少.答案对10^9+7取模. Input 有多组测试数据. 第一个一

BZOJ 4816: [Sdoi2017]数字表格

二次联通门 : BZOJ 4816: [Sdoi2017]数字表格 /* BZOJ 4816: [Sdoi2017]数字表格 莫比乌斯反演 妈呀,我的μ没有啦 */ #include <cstdio> #include <iostream> #define rg register #define Max 1000050 #define mo 1000000007 inline int min (int a, int b) { return a < b ? a : b; } i

[BZOJ4816][SDOI2017]数字表格(莫比乌斯反演)

4816: [Sdoi2017]数字表格 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1259  Solved: 625[Submit][Status][Discuss] Description Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)

Bzoj4816 [Sdoi2017]数字表格

Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 646  Solved: 296 Description Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)],其中gcd(i,j)表示i, j的最大公约数.Doris的表格中共有n×m个数,她想知道这

P3704 [SDOI2017]数字表格

#include<iostream> #include<cstdio> #include<cstring> #define LL long long #define maxn 1000009 #define N maxn+10 #define M 1000000007 using namespace std; int n,m; int q; LL ksm(LL a,LL p){ LL ans=1; for(;p;p>>=1,a=a*a%M){ if(p&am

codevs 5962 [SDOI2017]数字表格

输入描述 Input Description  [题解] 对于蓝色部分预处理前缀积. 然后在用除法分块搞一下. O(Q*sqrt(min(n,m))*logn+nlogn) #include<cstdio> #include<iostream> using namespace std; typedef long long ll; const int N=1e6+5; const ll mod=1e9+7; int T,n,m,tot,mu[N],prime[N/3];bool ch

BZOJ4816 Sdoi2017数字表格

一开始只推出O(TN)的做法,后来看了看发现再推一步就好了. 我们只需要枚举gcd就可以啦. 然后我们改变一下枚举顺序 设T为dk 预处理中间那部分前缀积就好了. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+10,mod=1e9+7; 4 int n,m,p[N/2],miu[N],g[N],f[N],inv[N],cnt;bool v[N]; 5 typedef long long ll; 6 int

loj SDOI2017数字表格 先存下

\(\prod \limits_{i=1}^{n}\prod\limits_{j=1}^{m}f[gcd(i,j)]\) \(\prod\limits_{k=1}^{n}f[k]^{\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)==k]}\) 幂我们很熟悉 就是 \(g(x)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)==x]=\sum\limits_{i=1}^{\frac{n}