codeforces803F 2100分容斥原理 + 莫比烏斯函數

題目傳送門

題意:

給你 \dpi{150}n 個數的序列 \dpi{150}a ,問你 gcd = 1 的子序列方案數。

數據範圍: 1 \leqslant n \;,\; a_i \leqslant 10^5 。

題解:

ans = cal(num[1]) - \sum cal(num[p]) + \sum cal(num[k])

p 的質因子個數是奇數個,且沒有相同的質因子。

\dpi{150} k 的質因子個數是偶數個,且沒有相同的質因子。

num[i] 表示序列中 i 的倍數的個數。

cal(x) 表示 x 個數形成的非空集合的個數。

這就是莫比烏斯函數。

感受:

關鍵是分析本質不同的質因子。

代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
const ll mod = 1e9 + 7 ;
int n , cnt[maxn] , num[maxn] ;
bool vis[maxn] ;
int prime[maxn] ;
int mu[maxn] ;
void get_mu()
{
   int up = 1e5 ;
   int cnt = 0 ;
   mu[1] = 1 ;
   for(int i = 2 ; i <= up ; i ++)
   {
     if(!vis[i])  prime[++ cnt] = i , mu[i] = -1 ;
     for(int j = 1 ; j <= cnt && prime[j] * i <= up ; j ++)
     {
       vis[prime[j] * i] = 1 ;
       if(i % prime[j] == 0)  break ;
        else  mu[i * prime[j]] = -mu[i] ;
     }
   }
}
void init()
{
	int up = 1e5 ;
	num[1] = n ;
	for(int i = 2 ; i <= up ; i ++)
	  for(int j = i ; j <= up ; j += i)
	    num[i] += cnt[j] ;
}
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 cal(int x)
{
	ll ans = 0 ;
	ans = qpow(2ll , ll(x)) ;
	ans = (ans - 1 + mod) % mod ;
	return ans ;
}
void solve()
{
	int up = 1e5 ;
	ll ans = cal(num[1]) ;
	for(int i = 2 ; i <= 1e5 ; i ++)
	{
		ans += ll(mu[i]) * cal(num[i]) ;
		ans %= mod ;
	}
	ans = (ans + mod) % mod ;
	printf("%lld\n" , ans) ;
}
int main()
{
	scanf("%d" , &n) ;
	memset(cnt , 0 , sizeof(cnt)) ;
	memset(num , 0 , sizeof(num)) ;
	for(int i = 1 ; i <= n ; i ++)
	{
		int x ;
		scanf("%d" , &x) ;
		cnt[x] ++ ;
	}
	get_mu() ;
	init() ;
	solve() ;
	return 0 ;
}

 

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