Codeforces 585E Present for Vitalik the Philatelist (莫比乌斯反演)

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <algorithm>  
#include <queue>  
#include <set>  
#include <ctime>  
#include <cstdlib>  
using namespace std;  


#define inf 0x3f3f3f3f
#define N 10000020
#define M 1000020
#define LL long long
#define mod 1000000007
#define ls (i << 1)
#define rs (ls | 1)
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define B 350


int p[N/10], cnt;
short int mu[N];
bool np[N];
int p2[N];
int n;
int h[N];
int g[N];
int c[N];

int a[N];
void init() {
	mu[1] = 1;
	for(int i = 2; i < N; ++i) {
		if(!np[i]) {
			p[cnt++] = i;
			mu[i] = -1;
		}
		for(int j = 0; j < cnt && i * p[j] < N; ++j) {
			int t = i * p[j];
			np[t] = 1;
			if(i % p[j] == 0) {
				mu[t] = 0;
				break;
			}
			mu[t] = mu[i] * -1;
		}
	}
	p2[0] = 1;
	for(int i = 1; i < N; ++i) p2[i] = p2[i-1] * 2 % mod;
	h[1] = g[1] = p2[n] - 1;
	a[1] = n;
	for(int i = 2; i < N; ++i) {
		for(int j = i + i; j < N; j += i) {
			a[i] += a[j];
		}
		if(a[i] > 0) h[i] = g[i] = p2[a[i]] - 1;
	}

	for(int j = 2; j < N; ++j) {
		if(mu[j] == 0) continue;
		for(int d = j, i = 1; d < N; d += j, ++i) {
			h[i] += 1LL * mu[j] * g[d] % mod;
			if(h[i] >= mod) h[i] -= mod;
			if(h[i] < 0) h[i] += mod;
		}
	}
	for(int i = 1; i < N; ++i) {
		if(mu[i] == 0) continue;
		for(int j = i; j < N; j += i) {
			c[j] += 1LL * mu[i] * a[i] % mod;
			if(c[j] < 0) c[j] += mod;
			if(c[j] >= mod) c[j] -= mod;
		}
	}


}




int readint() {
	char c;
	while((c = getchar()) && !(c >= '0' && c <= '9'));
	int ret = c - 48;
	while((c = getchar()) && c >= '0' && c <= '9')
		ret = ret * 10 + c - 48;
	return ret;
}

int main() {


	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		int x;
		x = readint();
		a[x]++;
	}
	init();
	LL ans = 0;
	for(int i = 2; i < N; ++i) {
		ans += 1LL * c[i] * h[i];
	}
	ans %= mod;
	printf("%d\n", ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值