• bzoj4816:[Sdoi2017]数字表格


    传送门

    我是真的垃圾啊,我就不能独立的做完一道题吗

    这个题还是莫比乌斯反演

    但是很神奇的出现了(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} floorlfloor frac{m}{d} floor\ g(d)=sum_{d|x}mu(frac{x}{d})F(x)=sum_{d|x}mu(frac{x}{d})lfloor frac{n}{x} floorlfloor frac{m}{x} floor\ ]

    那么答案式就可以进行转换

    [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} floorlfloor frac{m}{T} floor\ ]

    然后将(T)提出来

    [ans=prod_{T=1}^{n}prod_{d|T}f(T)^{mu(frac{T}{d})lfloor frac{n}{T} floorlfloor frac{m}{T} floor} ]

    然后发现(lfloor frac{n}{T} floorlfloor frac{m}{T} floor)可以整除分块

    再改一下

    [ans=prod_{T=1}^{n}prod_{d|T}(f(T)^{mu(frac{T}{d})})^{lfloor frac{n}{T} floorlfloor frac{m}{T} floor} ]

    最后怎么解决(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
    ",ans);
    	}
    }
    
  • 相关阅读:
    网络故障排除工具 | 快速定位网络故障
    Brocade博科光纤交换机zone配置
    博科Brocade 300光纤交换机配置zone教程
    游戏开发
    第8章 图
    第7章 二叉树
    第6章 树型结构
    第5章 递归
    第4章 字符串、数组和特殊矩阵
    第3章 顺序表的链式存储
  • 原文地址:https://www.cnblogs.com/lcxer/p/10587907.html
Copyright © 2020-2023  润新知