1. 程式人生 > >bzoj4816:[Sdoi2017]數字表格

bzoj4816:[Sdoi2017]數字表格

ble sdi print reg 通過 題解 mes bool ++

傳送門

我是真的有那麽癆,我就真的不能獨立的做完一道題嗎

這個題還是莫比烏斯反演

但是很神奇的出現了\(\prod\),先不管它,先把答案式寫出來
\[ ans=\prod_{i=1}^{n}\prod_{j=1}^{m}f[gcd(i,j)] \]
然後一貫的套路,枚舉\(gcd\)的值
\[ ans=\prod_{d=1}^{n}\prod_{i=1}^{n}\prod_{j=1}^{m}\prod_{gcd(i,j)==d}f(d) \]

然後發現\(f(d)\)的個數等於\(gcd(i,j)=d\)的個數

那麽我們就可以把答案式寫成這樣
\[ ans=\prod_{d=1}^{n}f(d)^{\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]} \]


然後設\(g(d)\)\(F(d)\)反演
\[ g(d)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]\F(d)=\sum_{d|x}g(x)=\sum_{i=1}^{n}\sum_{j=1}^{m}[d|gcd(i,j)]=\lfloor \frac{n}{d}\rfloor\lfloor \frac{m}{d}\rfloor\g(d)=\sum_{d|x}\mu(\frac{x}{d})F(x)=\sum_{d|x}\mu(\frac{x}{d})\lfloor \frac{n}{x}\rfloor\lfloor \frac{m}{x}\rfloor\\]

那麽答案式就可以進行轉換
\[ ans=\prod_{d=1}^{n}f(d)^{g(d)} \]
然後我們就得到了一個\(O(Tn)\)的做法,並不能通過

但是我只會到這一步,又得去看題解,發現題解多了幾步轉化
\[ g(d)=\sum_{T=1}^{n}\mu(\frac{T}{d})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor\\]
然後將\(T\)提出來
\[ ans=\prod_{T=1}^{n}\prod_{d|T}f(T)^{\mu(\frac{T}{d})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor} \]


然後發現\(\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor\)可以整除分塊

再改一下
\[ ans=\prod_{T=1}^{n}\prod_{d|T}(f(T)^{\mu(\frac{T}{d})})^{\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor} \]
最後怎麽解決\(f(T)^{\mu(\frac{T}{d})}\)的問題呢,暴力預處理枚舉倍數就好了

最後可以做到\(O(\sqrt{n}*logn)\)單組詢問

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=1e6+10,mod=1e9+7;
int T,n,m,f[maxn],nf[maxn],mu[maxn],pri[maxn],tot,ans,g[maxn];bool vis[maxn];
int mi(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=1ll*ans*a%mod;
        b>>=1,a=1ll*a*a%mod;
    }
    return ans;
}
void prepare()
{
    mu[1]=1;
    for(rg int i=2;i<=1e6;i++)
    {
        if(!vis[i])pri[++tot]=i,mu[i]=-1;
        for(rg int j=1;j<=tot&&pri[j]*i<=1e6;j++)
        {
            vis[pri[j]*i]=1;
            if(!(i%pri[j]))break;
            else mu[i*pri[j]]=-mu[i];
        }
    }
    f[1]=nf[1]=nf[0]=g[1]=1;
    for(rg int i=2;i<=1e6;i++)g[i]=1,f[i]=(f[i-1]+f[i-2])%mod,nf[i]=mi(f[i],mod-2);
    for(rg int i=1;i<=1e6;i++)
        if(mu[i])
            for(rg int j=i;j<=1e6;j+=i)
                g[j]=1ll*g[j]*(mu[i]==1?f[j/i]:nf[j/i])%mod;
    for(rg int i=2;i<=1e6;i++)g[i]=1ll*g[i]*g[i-1]%mod,nf[i]=mi(g[i],mod-2);
}
int main()
{
    read(T),prepare();
    while(T--)
    {
        read(n),read(m);if(n>m)swap(n,m);ans=1;
        for(rg int i=1,j;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            int t=1ll*(n/i)*(m/i)%(mod-1);
            ans=1ll*ans*mi(1ll*g[j]*nf[i-1]%mod,t)%mod;
        }
        printf("%d\n",ans);
    }
}

bzoj4816:[Sdoi2017]數字表格