codeforces900D 2100分莫比烏斯反演

題目傳送門

題意:

正整數序列 \dpi{150}a ,序列的 gcd 是 x ,並且序列之和是 y 。

問這樣的序列個數,答案取模。

數據範圍:1 \leqslant x \;,\; y \leqslant 10^9 。

題解:

容易發現存在這樣的序列等價於 x \mid y 。

簡化一下題意,這樣的序列是 gcd 是 1 ,並且序列之和是 \frac{y}{x} 。

gcd 是 1 ,並且序列之和是 x 的函數 f(x) 是不好求的。

序列之和是 x 的函數 g(x) 是很好求的。 

這樣就考慮莫比烏斯反演了。

想一想會發現, g(x) = \sum_{d\mid x}f(\frac{x}{d}) 。

反演一下,f(x) = \sum_{d\mid x} \mu(d) g(\frac{x}{d}) 。

通過插板法可以知道 g(x) = 2 ^ {x - 1} 。

感受:

容斥題,可以考慮莫比烏斯反演。

代碼:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const ll mod = 1e9 + 7 ;
ll qpow(ll a , ll b)
{
   ll ans = 1 ; 
   a %= mod ;
   while(b)
   {
     if(b & 1)  ans = (ans * a) % mod ;
     b >>= 1 , a = (a * a) % mod ;
   }
   return ans % mod ;
}
ll get_mu(ll n)
{
    ll x = n , temp = n ;
    ll cnt = 0 , now = 0 ;
    for(ll i = 2 ; i * i <= x ; i ++)
	{
        now = 0 ;
        if(x % i == 0)
		{
            while(x % i == 0)  now ++ , x /= i ;
            if(now > 1) return 0 ;
            cnt ++ ;
        }
    }
    if(x != 1) cnt ++ ;
    return (cnt & 1) ? -1 : 1 ;
}
ll g(ll x)
{
	return qpow(2ll , x - 1) ;
}
void solve(ll x)
{
	ll ans = 0 ;
	for(ll d = 1 ; d * d <= x ; d ++)
	{
		if(x % d != 0)  continue ;
		ans += get_mu(d) * g(x / d) ;
		if(d * d != x)
		  ans += get_mu(x / d) * g(d) ;
		ans %= mod ;
	}
	ans = (ans + mod) % mod ;
	printf("%lld\n" , ans) ;
}
int main()
{
	ll x , y ;
	scanf("%lld%lld" , &x , &y) ;
	if(y % x != 0){printf("0\n") ; return 0 ;}
	solve(y / x) ; 
	return 0 ;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章