zoukankan      html  css  js  c++  java
  • bzoj 4816

    这题是莫比乌斯反演的典型题也是很有趣的题。

    题意:求prod_{k=1}^{min(n,m)}f(k)^{sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)==k]},其中f为为斐波那契数列

    那么首先观察一下指数,发现是我们熟悉的形式,可以转化成这样的形式:prod_{k=1}^{min(n,m)}f(k)^{sum_{d=1}^{min([n/k],[m/k])}mu(d)*[n/k]*[m/k]}

    令T=kd,且假设n<m,有:

    prod_{T=1}^{n}prod_{k|T}f(k)^{mu(T/k)*[n/T]*[m/T]}

    g(T)=prod_{k|T}f(k)^{mu(T/k)}

    则原式=prod_{T=1}^{n}g(T)^{[n/T]*[m/T]}

    这样的话我们的步骤就是这样的:

    线性筛出莫比乌斯函数,同时递推求出f

    然后利用f和莫比乌斯函数求出g(枚举倍数,这样把时间复杂度控制在调和级数级别),注意到有时会出现分数(莫比乌斯函数值为-1时),所以对上面的每个f需要求出对应地逆元(费马小定理)

    然后对g求出前缀积,这样就可以利用数论分块在根号级的时间内求出答案了,但由于是乘积式,所以在提取一段乘积的时候会出现除法,所以还要对求出的前缀积求出逆元。

    注意上面的都是要预处理出的内容

    然后就水到渠成了

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    #define mode 1000000007
    using namespace std;
    ll g[1000005];
    ll f[1000005];
    ll inv[1000005];
    int mu[1000005];
    int pri[1000005];
    ll mul[1000005];
    ll minv[1000005];
    int cnt=0;
    bool used[1000005];
    int T,n,m;
    ll pow_mul(ll x,ll y)
    {
    	ll ans=1;
    	while(y)
    	{
    		if(y&1)
    		{
    			ans*=x;
    			ans%=mode;
    		}
    		x*=x;
    		x%=mode;
    		y/=2;
    	}
    	return ans;
    }
    void init()
    {
    	mu[1]=1;
    	f[1]=1;
    	g[1]=1;
    	inv[1]=1;
    	for(int i=2;i<=1000000;i++)
    	{
    		f[i]=f[i-1]+f[i-2];
    		f[i]%=mode;
    		g[i]=1;
    		inv[i]=pow_mul(f[i],mode-2);
    		if(!used[i])
    		{
    			pri[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&i*pri[j]<=1000000;j++)
    		{
    			used[i*pri[j]]=1;
    			if(i%pri[j]==0)
    			{
    				mu[i*pri[j]]=0;
    				break;
    			}
    			mu[i*pri[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=1000000;i++)
    	{
    		for(int j=1;i*j<=1000000;j++)
    		{
    			if(!mu[j])
    			{
    				continue;
    			}else if(mu[j]==1)
    			{
    				g[i*j]*=f[i];
    				g[i*j]%=mode;
    			}else
    			{
    				g[i*j]*=inv[i];
    				g[i*j]%=mode;
    			}
    		} 
    	}
    	mul[0]=1;
    	minv[0]=1;
    	for(int i=1;i<=1000000;i++)
    	{
    		mul[i]=mul[i-1]*g[i]%mode;
    		minv[i]=pow_mul(mul[i],mode-2);
    	}
    }
    ll solve(int x,int y)
    {
    	if(x>y)
    	{
    		swap(x,y);
    	}
    	ll ans=1;
    	int last=0;
    	for(int i=1;i<=x;i=last+1)
    	{
    		last=min(x/(x/i),y/(y/i));
    		ans*=pow_mul(mul[last]*minv[i-1]%mode,(ll)(x/i)*(ll)(y/i)%(mode-1));
    		ans%=mode;
    	}
    	return ans;
    }
    int main()
    {
    	init();
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&m);
    		printf("%lld
    ",solve(n,m));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Luogu P4727 [HNOI2009]图的同构记数
    ARC 101 E
    JSOI2019 Round2 游记
    JSOI2019 Round1(十二省联考)游记
    Technocup 2019
    Codeforces Round #533 (Div. 2)比赛总结
    学习链接
    2018.12.29-2018.1.9安师大附中集训
    关于考试
    NOIP2018提高组 游记
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764137.html
Copyright © 2011-2022 走看看