• 【BZOJ4816】【SDOI2017】数字表格 [莫比乌斯反演]


    数字表格

    Time Limit: 50 Sec  Memory Limit: 128 MB
    [Submit][Status][Discuss]

    Description

      Doris刚刚学习了fibonacci数列。用f[i]表示数列的第i项,那么
      f[0]=0
      f[1]=1
      f[n]=f[n-1]+f[n-2],n>=2
      Doris用老师的超级计算机生成了一个n×m的表格,第i行第j列的格子中的数是f[gcd(i,j)],其中gcd(i,j)表示i,j的最大公约数。Doris的表格中共有n×m个数,她想知道这些数的乘积是多少。答案对10^9+7取模。

    Input

      第一个一个数T,表示数据组数。
      接下来T行,每行两个数n,m

    Output

      输出T行,第i行的数是第i组数据的结果

    Sample Input

      3
      2 3
      4 5
      6 7

    Sample Output

      1
      6
      960

    HINT

      T<=1000,1<=n,m<=10^6

    Solution

      运用莫比乌斯反演,得到式子:

      这样我们对于内外分块即可,复杂度为O(n^(0.75)*T)。

      然后我们会发现在BZOJ上过不去,怎么办呢?卡常!BearChild运用了如下的卡常技巧:

        1.  读入优化; 2. O(n)预处理逆元; 3. 内嵌汇编实现乘和取模; 4. 记录n/i,避免多次除法。

    Code

      1 #include<iostream>  
      2 #include<string>  
      3 #include<algorithm>  
      4 #include<cstdio>  
      5 #include<cstring>  
      6 #include<cstdlib>  
      7 #include<cmath>
      8 using namespace std; 
      9 typedef long long s64;
     10  
     11 const int ONE = 1e6+5;
     12 const int MOD = 1e9+7;
     13 const int PHI = 1e9+6;
     14  
     15 int T;
     16 int n,m;
     17 int prime[ONE],p_num,miu[ONE];
     18 int F[ONE];
     19 bool isp[ONE];
     20 s64 Ans;
     21  
     22 int get() 
     23 {
     24         int res=1,Q=1;  char c;
     25         while( (c=getchar())<48 || c>57)
     26         if(c=='-')Q=-1;
     27         if(Q) res=c-48; 
     28         while((c=getchar())>=48 && c<=57) 
     29         res=res*10+c-48; 
     30         return res*Q; 
     31 }
     32  
     33 int Quickpow(int a,int b)
     34 {
     35         int res = 1;
     36         while(b)
     37         {
     38             if(b&1) res = (s64)res*a%MOD;
     39             a = (s64)a*a%MOD;
     40             b>>=1;
     41         }
     42         return res;
     43 }
     44  
     45 void Deal_first(int MaxN)
     46 {
     47         F[1]=1;
     48         F[0]=0; for(int i=2; i<=MaxN; i++) F[i] = ((s64)F[i-1]+F[i-2]) % MOD;
     49         F[0]=1; for(int i=2; i<=MaxN; i++) F[i] = (s64)F[i]*F[i-1] % MOD;
     50          
     51         miu[1] = 1;
     52         for(int i=2; i<=MaxN; i++)
     53         {
     54             if(!isp[i])
     55                 prime[++p_num] = i, miu[i] = -1;
     56             for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++)
     57             {
     58                 isp[i * prime[j]] = 1;
     59                 if(i % prime[j] == 0)
     60                 {
     61                     miu[i * prime[j]] = 0;
     62                     break;
     63                 }
     64                 miu[i * prime[j]] = -miu[i];
     65             }
     66             miu[i] += miu[i-1];
     67         }
     68 }
     69  
     70 int f(int n,int m)
     71 {
     72         if(n > m) swap(n,m);
     73         s64 Ans = 0;
     74         for(int i=1,j=0; i<=n; i=j+1)
     75         {
     76             j = min(n/(n/i), m/(m/i));
     77             Ans += (s64)(n/i) * (m/i)%PHI * ((s64)(miu[j] - miu[i-1] + PHI)%PHI) % PHI;
     78             Ans %= PHI;
     79         }
     80         return Ans;
     81 }
     82  
     83 void Solve()
     84 {
     85         n=get();    m=get();
     86         if(n > m) swap(n,m);
     87         Ans = 1;
     88         for(int i=1,j=0; i<=n; i=j+1)
     89         {
     90             j = min(n/(n/i), m/(m/i));
     91             Ans = Ans * Quickpow( (s64)F[j] * Quickpow(F[i-1],MOD-2) % MOD , f(n/i,m/i) % PHI) % MOD;
     92         }
     93         printf("%lld
    ",Ans);
     94 }
     95  
     96 int main()
     97 {
     98         Deal_first(ONE-1);
     99         T = get();
    100         while(T--)
    101             Solve();
    102         return 0;
    103 }
    非卡常版
      1 #include<iostream>  
      2 #include<string>  
      3 #include<algorithm>  
      4 #include<cstdio>  
      5 #include<cstring>  
      6 #include<cstdlib>  
      7 #include<cmath>
      8 using namespace std; 
      9 typedef long long s64;
     10  
     11 const int ONE = 1e6+2;
     12 const int MOD = 1e9+7;
     13 const int PHI = 1e9+6;
     14  
     15 int T;
     16 int n,m;
     17 int prime[ONE],p_num,miu[ONE];
     18 int Niyu[ONE];
     19 int F[ONE];
     20 bool isp[ONE];
     21 int Ans;
     22  
     23 inline int get() 
     24 {
     25         int res=1,Q=1;  char c;
     26         while( (c=getchar())<48 || c>57)
     27         if(c=='-')Q=-1;
     28         if(Q) res=c-48; 
     29         while((c=getchar())>=48 && c<=57) 
     30         res=res*10+c-48; 
     31         return res*Q; 
     32 }
     33 
     34 inline int modmul(const int &a, const int &b,const int &M)
     35 {
     36         int ret;
     37         __asm__ __volatile__("	mull %%ebx
    	divl %%ecx
    " : "=d"(ret) : "a"(a), "b"(b), "c"(M));
     38         return ret;
     39 }
     40 
     41 inline int Quickpow(int a,int b)
     42 {
     43         int res = 1;
     44         while(b)
     45         {
     46             if(b&1) res = modmul(res,a,MOD);
     47             a = modmul(a,a,MOD);
     48             b>>=1;
     49         }
     50         return res;
     51 }
     52  
     53 inline void Deal_first(int MaxN)
     54 {
     55         F[0]=0; F[1]=1;
     56         int val=1;
     57         for(int i=2; i<=MaxN; i++)
     58         {
     59             F[i] = F[i-1]+F[i-2];
     60             if(F[i] >= MOD) F[i] -= MOD;
     61             val = modmul(val,F[i],MOD);
     62         }
     63         Niyu[MaxN] = Quickpow(val, MOD-2);
     64         for(int i=MaxN-1;i>=1;i--) Niyu[i] = modmul(Niyu[i+1],F[i+1],MOD);
     65         Niyu[0] = Niyu[1]; F[0]=1;
     66         for(int i=1; i<=MaxN; i++) F[i] = modmul(F[i],F[i-1],MOD);
     67          
     68         miu[1] = 1;
     69         for(int i=2; i<=MaxN; i++)
     70         {
     71             if(!isp[i])
     72                 prime[++p_num] = i, miu[i] = -1;
     73             for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++)
     74             {
     75                 isp[i * prime[j]] = 1;
     76                 if(i % prime[j] == 0)
     77                 {
     78                     miu[i * prime[j]] = 0;
     79                     break;
     80                 }
     81                 miu[i * prime[j]] = -miu[i];
     82             }
     83             miu[i] += miu[i-1];
     84         }
     85 }
     86  
     87 inline int f(int n,int m)
     88 {
     89         if(n > m) swap(n,m);
     90         int Ans = 0;
     91         for(int i=1,j=0; i<=n; i=j+1)
     92         {
     93             int x=n/i, y=m/i;
     94             j = min(n/x, m/y);
     95             Ans = ((s64)Ans + modmul(modmul(x,y,PHI) , ((s64)miu[j] - miu[i-1] + PHI), PHI) )%PHI;
     96         }
     97         return Ans;
     98 }
     99  
    100 inline void Solve()
    101 {
    102         n=get();    m=get();
    103         if(n > m) swap(n,m);
    104         Ans = 1;
    105         for(int i=1,j=0; i<=n; i=j+1)
    106         {
    107             int x=n/i, y=m/i;
    108             j = min(n/x, m/y);
    109             Ans = (s64)modmul(Ans , Quickpow( modmul(F[j],Niyu[i-1],MOD) , f(x,y)), MOD);
    110         }
    111         printf("%d
    ",Ans);
    112 }
    113  
    114 int main()
    115 {
    116         Deal_first(ONE-1);
    117         T = get();
    118         while(T--)
    119             Solve();
    120         return 0;
    121 }
    卡常版
  • 相关阅读:
    java 异常处理
    c/c++ 多维数组和指针
    c/c++ 数组和指针
    c/c++ 数组 数组的引用,指针数组的引用
    c/c++ 标准库 迭代器(iterator)
    c/c++ 标准库 vector
    c/c++ 标准库 string
    c/c++ 模板与STL小例子系列<三> traits
    c++ 右值引用,move关键字
    c/c++ 右值引用
  • 原文地址:https://www.cnblogs.com/BearChild/p/6696543.html
Copyright © 2020-2023  润新知