POJ3904 & SPOJ & 洛谷SP4191 Sky Code 莫比乌斯反演

题目链接(略多):
SPOJ
POJ3904
洛谷SP4191
vjudge
cn.vjudge.net

题目大意:

给出 n n n个数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an,要求从 n n n个数中选出 4 4 4个数 a , b , c , d a,b,c,d a,b,c,d,要求 g c d ( a , b , c , d ) = 1. gcd(a,b,c,d)=1. gcd(a,b,c,d)=1.
求共有多少种取法。
数据范围: n &lt; = 1 0 4 , 1 &lt; = a i &lt; = 1 0 4 n&lt;=10^4,1&lt;=a_i&lt;=10^4 n<=104,1<=ai<=104,每个测试点包含多组数据。


暴力:枚举四个选到的数,然后大力求 g c d . . . gcd... gcd...
时间复杂度 O ( n 4 l o g n ) . . . O(n^4logn)... O(n4logn)... n = 1 0 4 n=10^4 n=104的情况下肯定要凉qwq
于是我们珂以考虑上网搜题解……
莫比乌斯反演?
于是我学了一下……(这道题)好像也不是很难?qwq
莫比乌斯反演的主要内容就一条:
F ( n ) = Σ d ∣ n f ( d ) \large F(n)=\Large \Sigma\large_{d|n} {f(d)} F(n)=Σdnf(d),则有 f ( n ) = Σ d ∣ n μ ( d ) F ( n d ) \large f(n)=\Large \Sigma\large_{d|n}\mu(d)F(\frac{n}{d}) f(n)=Σdnμ(d)F(dn) ——(1)
但有时候用的是另外一种形式:
F ( n ) = Σ n ∣ d f ( d ) \large F(n)=\Large \Sigma\large_{n|d} {f(d)} F(n)=Σndf(d),则有 f ( n ) = Σ n ∣ d μ ( d n ) F ( d ) \large f(n)=\Large\Sigma\large_{n|d}\mu(\frac{d}{n})F(d) f(n)=Σndμ(nd)F(d) ——(2)
如果这里给出详细证明的话会变得很长……所以这里就不证明了……可以看我的博客qwq
但是这两个玄学式子对这道题有什么用呢?
不妨让 f ( n ) f(n) f(n)表示在所有数中选出 4 4 4个,且 4 4 4个数的 g c d gcd gcd n n n的选法。
F ( n ) F(n) F(n)表示在所有数中选出 4 4 4个,且 4 4 4个数的 g c d gcd gcd n n n的倍数的选法。
现在需要求的是 f ( 1 ) f(1) f(1)
珂以发现:
F ( n ) = Σ n ∣ d f ( d ) \large F(n)=\Large \Sigma\large_{n|d} {f(d)} F(n)=Σndf(d)
要注意的是,这里 d ≤ m a x ( a 1 , a 2 , . . . , a n ) d\leq max(a_1,a_2,...,a_n) dmax(a1,a2,...,an),否则 f ( d ) = 0 f(d)=0 f(d)=0(最大公因数不可能大于所有数的最大值)
然后把这个式子往(2)一套,得到
f ( n ) = Σ n ∣ d μ ( d n ) F ( d ) \large f(n)=\Large\Sigma\large_{n|d}\mu(\frac{d}{n})F(d) f(n)=Σndμ(nd)F(d)
所以
m a x a = m a x ( a 1 , a 2 , . . . , a n ) maxa=max(a_1,a_2,...,a_n) maxa=max(a1,a2,...,an)
f ( 1 ) = Σ 1 ∣ d μ ( d 1 ) F ( d ) = Σ d = 1 m a x a μ ( d ) F ( d ) \large f(1)=\Large\Sigma\large_{1|d}\mu(\frac{d}{1})F(d)=\Large\Sigma\large_{d=1}^{maxa}\mu(d)F(d) f(1)=Σ1dμ(1d)F(d)=Σd=1maxaμ(d)F(d)
所以如果知道了所有的 μ ( i ) 和 F ( i ) \mu(i)和F(i) μ(i)F(i),就珂以在 O ( n ) O(n) O(n)的时间复杂度内求解qwq。
然后 μ ( i ) \mu(i) μ(i)是珂以线性筛的……方法和筛质数差不多……具体见代码qwq
F ( i ) F(i) F(i)的求法也比较简单,把这些数分解质因数,令 n u m [ i ] num[i] num[i]表示有多少个数能整除 i i i,在分解质因数时求出所有的 n u m . num. num.
显然, F ( i ) = C n u m [ i ] 4 F(i)=\Large C_{num[i]}^4 F(i)=Cnum[i]4
所以 F ( i ) F(i) F(i)能在 O ( n n ) O(n\sqrt n) O(nn )复杂度内筛出来。
然后算出答案就珂以了……qwq

代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#define re register int
#define rl register ll
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline void write(int x) {
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
namespace I_Love {

const int Size=10005;
int n,tot,a[Size],p[Size],prime[Size];
bool vis[Size];
void getp(int maxn) {
	//线性筛莫比乌斯函数
	p[1]=1;
	for(re i=2; i<=maxn; i++) {
		if(!vis[i]) {
			prime[++tot]=i;
			p[i]=-1;
		}
		for(re j=1; j<=tot; j++) {
			int now=i*prime[j];
			if(now>maxn)	break;
			vis[now]=true;
			//如果i能整除prime[j],就break 
			//可以证明这样i*prime[j+1]也一定会被筛到 
			if(!(i%prime[j]))	break;
			p[now]=-p[i];
		}
	}
}
ll num[Size],F[Size];
void Divide(int x) {
	int sx=sqrt(x);
	for(re i=1; i<=sx; i++) {
		if(!(x%i)) {
			num[i]++;
			num[x/i]++;
		}
	}
	if(sx*sx==x) {
		num[sx]--;
	}
}
void Fujibayashi_Ryou() {
	getp(10000);
	while(scanf("%d",&n)==1) {
		int maxn=0;
		for(re i=1; i<=n; i++) {
			a[i]=read();
			if(a[i]>maxn)	maxn=a[i];
		}
		memset(num,0,sizeof(num));
		for(re i=1; i<=n; i++) {
			//分解质因数,同时求出所有的num
			Divide(a[i]);
		}
		ll ans=0;
		for(re i=1; i<=maxn; i++) {
			F[i]=num[i]*(num[i]-1)*(num[i]-2)*(num[i]-3)/24;
			ans+=F[i]*p[i];
		}
		printf("%lld\n",ans);
	}
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值