zoukankan      html  css  js  c++  java
  • 【洛谷P3704】数字表格

    题目

    题目链接:https://www.luogu.com.cn/problem/P3704
    Doris 用老师的超级计算机生成了一个 (n imes m) 的表格,
    (i) 行第 (j) 列的格子中的数是 (fib_{gcd(i,j)}),其中 (gcd(i,j)) 表示 (i,j) 的最大公约数。
    Doris 的表格中共有 (n imes m) 个数,她想知道这些数的乘积是多少。
    答案对 (10^9+7) 取模。
    (Qleq 1000;n,mleq 10^6)

    思路

    [prod_{d}prod^{n}_{i=1}prod^{m}_{j=1}[gcd(i,j)=d] ext{fib}(d) ]

    [=prod_{d} ext{fib}(d)^{sum^{lfloorfrac{n}{d} floor}_{i=1} sum^{lfloorfrac{m}{d} floor}_{j=1}[gcd(i,j)=1]} ]

    [=prod_{d} ext{fib}(d)^{sum_{i}mu(i)lfloorfrac{n}{id} floorlfloorfrac{m}{id} floor} ]

    看到 (id) 果断令 (T=id),原式

    [=prod^{n}_{T=1}prod_{d|T} ext{fib}(d)^{mu(frac{T}{d})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor} ]

    [=prod^{n}_{T=1}left (prod_{d|T} ext{fib}(d)^{mu(frac{T}{d})} ight )^{lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor} ]

    括号外面整除分块,括号里面预处理即可。
    时间复杂度 (O(n(log p+log n)+Qsqrt{n}))(n,m) 同阶。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010,MOD=1e9+7;
    int Q,n,m,fib[N],inv[N],prm[N],mu[N];
    ll ans,g[N],h[N];
    bool v[N];
    
    void findprm(int n)
    {
    	mu[1]=1;
    	for (int i=2;i<=n;i++)
    	{
    		if (!v[i]) prm[++m]=i,mu[i]=-1;
    		for (int j=1;j<=m;j++)
    		{
    			if (i>n/prm[j]) break;
    			v[i*prm[j]]=1; mu[i*prm[j]]=-mu[i];
    			if (!(i%prm[j])) { mu[i*prm[j]]=0; break; }
    		}
    	}
    }
    
    ll fpow(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%MOD)
    		if (k&1) ans=ans*x%MOD;
    	return ans;
    }
    
    int main()
    {
    	findprm(N-1);
    	fib[1]=inv[1]=1;
    	for (int i=0;i<N;i++) g[i]=1;
    	for (int i=2;i<N;i++)
    	{
    		fib[i]=(fib[i-1]+fib[i-2])%MOD;
    		inv[i]=fpow(fib[i],MOD-2);
    		for (int j=i;j<N;j+=i)
    			g[j]=g[j]*(mu[j/i]==1 ? fib[i] : (mu[j/i]==0 ? 1 : inv[i]))%MOD;
    	}
    	h[0]=1;
    	for (int i=1;i<N;i++)
    	{
    		g[i]=g[i]*g[i-1]%MOD;
    		h[i]=fpow(g[i],MOD-2);
    	}
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%d%d",&n,&m);
    		ans=1;
    		for (int i=1,j;i<=min(n,m);i=j+1)
    		{
    			j=min(n/(n/i),m/(m/i));
    			ans=ans*fpow(g[j]*h[i-1]%MOD,1LL*(n/i)*(m/i))%MOD;
    		}
    		printf("%lld
    ",(ans%MOD+MOD)%MOD);
    	}
    	return 0;
    }
    
  • 相关阅读:
    poj2002 poj3432 正方形个数 (hash,二分)
    置换群
    poj1995快速幂取余
    poj3983 (24点)
    判断二叉树是否是完全二叉树
    判断两个二叉树是否同构(相似)
    poj2187 最远点对问题
    poj2079 求最大的三角形面积
    poj3714 最近点对
    Linq学习笔记延迟操作符(分区操作符)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14785136.html
Copyright © 2011-2022 走看看