NEFU 1507 Fibonacci And Gcd(莫比乌斯反演)

Fibonacci And Gcd
Problem:1507
Time Limit:1000ms
Memory Limit:65535K
Description

给定n和m求解上述式子
Input
第一行一个T,代表有T组数据,1<=T<=10
接下来T行每行两个数字n和m,1<=n,m<=1e6
Output
输出答案,每行代表一个答案
Sample Input
2
2 2
3 3
Sample Output
4
10

思路

从打表找规律会发现 gcd(Fi,Fj)=Fgcd(i,j) g c d ( F i , F j ) = F g c d ( i , j )
然后我们就可以开始推导了

i=1nj=1mgcd(Fi,Fj)=i=1nj=1mFgcd(i,j) ∑ i = 1 n ∑ j = 1 m g c d ( F i , F j ) = ∑ i = 1 n ∑ j = 1 m F g c d ( i , j )

i=1nj=1mFgcd(i,j)=d=1min(n,m)Fdi=1nj=1m[gcd(i,j)==d] ∑ i = 1 n ∑ j = 1 m F g c d ( i , j ) = ∑ d = 1 m i n ( n , m ) F d ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) == d ]

d=1min(n,m)Fdi=1nj=1m[gcd(i,j)==d]=d=1min(n,m)Fdi=1ndj=1nd[gcd(i,j)==1] ∑ d = 1 m i n ( n , m ) F d ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) == d ] = ∑ d = 1 m i n ( n , m ) F d ∑ i = 1 n d ∑ j = 1 n d [ g c d ( i , j ) == 1 ]

d=1min(n,m)Fdi=1ndj=1nd[gcd(i,j)==1]=d=1min(n,m)Fdi=1min(n,m)μ(i)nimi ∑ d = 1 m i n ( n , m ) F d ∑ i = 1 n d ∑ j = 1 n d [ g c d ( i , j ) == 1 ] = ∑ d = 1 m i n ( n , m ) F d ∑ i = 1 m i n ( n , m ) μ ( i ) n i ∗ m i

莫比乌斯函数用分块加速就行了

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const long long mod=1e9+7;
const int N=1e6+5;
long long f[N];
long long sum[N];
int vis[N];
int mu[N];
int prime[N];
int cnt;
void Init()
{
    memset(vis,0,sizeof(vis));
    mu[1] = 1;
    cnt = 0;
    for(int i=2; iif(!vis[i])
        {
            prime[cnt++] = i;
            mu[i] = -1;
        }
        for(int j=0; j1;
            if(i%prime[j]) mu[i*prime[j]] = -mu[i];
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
    f[1]=1;
    f[2]=1;
    for(int i=3; i1]+f[i-2])%mod;
    for(int i=1; i1]+mu[i];
}
long long get(int n,int m)
{
    long long ans=0;
    for(int i=1,last; i<=min(n,m); i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans+=(sum[last]-sum[i-1])*(n/i)*(m/i);
        ans=(ans+mod)%mod;
    }
    return ans;
}
int main()
{
    Init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        long long ans=0;
        for(int i=1; i<=min(n,m); i++)
        {
            ans=(ans%mod+f[i]%mod*get(n/i,m/i)%mod+mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(莫比乌斯反演,数论)