zoukankan      html  css  js  c++  java
  • 【刷题记录】SDOI2017数字表格

    https://www.luogu.org/problemnew/show/P3704
    题目描述
    Doris刚刚学习了fibonacci数列。用f[i]表示数列的第i项,那么
    f[0]=1,f[1]=1,
    f[n]=f[n-1]+f[n-2]
    Doris用老师的超级计算机生成了一个n×m的表格,
    第i行第j列的格子中的数是f[gcd(i,j)],其中gcd(i,j)表示i,j的最大公约数。
    Doris的表格中共有n×m个数,她想知道这些数的乘积是多少。
    答案对10^9+7取模。
    莫比乌斯反演

    直接上表达式(F(i)表示斐波那契数列第I项)
    ans=i=1mj=1nF((i,j))ans =prod_{i=1}^{m}prod_{j=1}^nF((i,j))
    =i=1min(m,n)F(i)(j,k)=i1=prod_{i=1}^{min(m,n)}{F(i)}^{sum_{(j,k)=i}1}
    分子是莫比乌斯反演中常见套路
    =i=1min(m,n)F(i)idμ(di)[nd][md]=prod_{i=1}^{min(m,n)}{F(i)}^{sum_{i|d}μ(frac d i)[ frac n d ][frac m d]}
    lnans=d=1min(m,n)[nd][md]idlnF(i)μ(di)lnans=sum_{d=1}^{min(m,n)}[frac n d][frac m d]sum_{i|d}lnF(i)μ(frac d i)
    ans=d=1min(n,m)(idF(i)μ(di))[nd][md]ans = prod_{d=1}^{min(n,m)}(prod_{i|d}F(i)^{μ(frac d i )})^{[ frac n d ][frac m d]}
    中间括号可以前缀积(理论上也可以线段树)但是注意使用前缀积需要处理逆元
    再使用快速乘
    这样总时间复杂度
    O(nlogn+Tlognn)O(nlogn+Tlognsqrt n)
    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define mod 1000000007
    #define N 1000000
    #define ll long long 
    int f[N+6],pre[N+6],prime[N+6],mu[N+6],tot;
    bool notprime[N+6];
    int fastpow(int x,int n)
    {
        if(!n)return 1;
        int ans = fastpow(x,n/2);
        ans = ((ll)ans *ans)%mod;
        if(n&1)
        ans = ((ll)ans *x)%mod;
        return ans;
    }
    int exgcd(ll &x,ll &y,int a, int b)
    {
        if(b==0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int ans = exgcd(x,y,b,a%b);
        ll t = x;
        x = y;
        y = t- (a/b)*y;
        return ans;
    }
    int inv(int m)
    {
        ll x,y;
        exgcd(x,y,m,mod);
        return (int)(((x%mod)+mod)%mod);
    }
    void init()
    {
        pre[0]=pre[1]=f[1]=notprime[1]=mu[1]=1;
        for(int i = 2; i <= N; i ++)
        {
            pre[i]=1;
            f[i]=((ll)f[i-1]+f[i-2])%mod;
            if(!notprime[i])
            {
                prime[++tot]=i;
                mu[i]=-1;
            }
            for(int j = 1 ; j <= tot && i*prime[j] <= N  ; j ++)
            {
                notprime[i*prime[j]]=1;
                if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                else 
                {
                    break;
                }
            }
        }
        for(int i = 1; i <= N ; i ++)
        for(int j = i; j <= N ; j += i)
        {   
            int t = f[i];
            if(mu[j/i]==-1)
            {
                t = inv(t);
            }
            else if(mu[j/i]==0)
            {
                t = 1;
            }
            pre[j]=((ll)pre[j]*t)%mod;
        }
        for(int i = 1; i <= N; i ++)
        {
            pre[i]=((ll)pre[i]*pre[i-1])%mod;
        }
    }
    int main()
    {
        int t;
        init();
        scanf("%d",&t);
        while(t--)
        {
            int ans = 1, n,m;
            scanf("%d%d",&n,&m);
            if(n>m)swap(m,n);
            for(int i = 1,last; i <= n; i = last +1 )
            {
                last = min(n/(n/i),m/(m/i));
                ans = ((ll)ans* fastpow((int)(((ll)pre[last]*inv(pre[i-1]))%mod),(n/i)*(m/i)))%mod;
                
            }
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    Docker Private Registry
    Dockerfile
    docker存储卷
    392. 判断子序列
    1576. 替换所有的问号
    270. 最接近的二叉搜索树值
    292. Nim 游戏
    680. 验证回文字符串 Ⅱ
    876. 链表的中间结点
    543. 二叉树的直径
  • 原文地址:https://www.cnblogs.com/akonoh/p/10216756.html
Copyright © 2011-2022 走看看