[CodeForces 839D] Winter is here(莫比乌斯反演) | 错题本

文章目录

题目

[CodeForces 839D] Winter is here

分析

m m m 是最大的数,枚举 gcd ⁡ = d \gcd = d gcd=d,子序列长度为 l l l,要求的就是 ∑ d = 2 m ∑ l = 1 n d ⋅ l ∑ 1 ≤ k 1 < k 2 < ⋯ < k l ≤ n [ gcd ⁡ i = 1 l a k i = d ] = ∑ d = 2 m ∑ l = 1 n d ⋅ l ∑ 1 ≤ k 1 < k 2 < ⋯ < k l ≤ n ( ∏ i = 1 l [ d ∣ a k i ] ) [ gcd ⁡ i = 1 l a k i d = 1 ] \begin{aligned} &\sum_{d = 2}^{m}\sum_{l = 1}^{n} d\cdot l \sum_{1 \leq k_1 < k_2 < \cdots < k_l \leq n} \left[\gcd_{i = 1}^l a_{k_i} = d\right] \\ = &\sum_{d = 2}^{m}\sum_{l = 1}^{n} d\cdot l \sum_{1 \leq k_1 < k_2 < \cdots < k_l \leq n} \left(\prod_{i = 1}^{l} [d | a_{k_i}] \right)\left[\gcd_{i = 1}^{l} \frac{a_{k_i}}{d} = 1\right]\end{aligned} =d=2ml=1ndl1k1<k2<<kln[i=1gcdlaki=d]d=2ml=1ndl1k1<k2<<kln(i=1l[daki])[i=1gcdldaki=1] 用莫比乌斯函数的基本性质 μ ∗ 1 = ε \mu * 1 = \varepsilon μ1=ε,枚举 a k i d \frac{a_{k_i}}{d} daki 的因数上式转化为: ∑ d = 2 m ∑ l = 1 n d ⋅ l ∑ p = 1 ⌊ m d ⌋ μ ( p ) ∑ 1 ≤ k 1 < k 2 < ⋯ < k l ≤ n ∏ i = 1 l [ ( d ⋅ p ) ∣ a k i ] = ∑ d = 2 m d ∑ p = 1 ⌊ m d ⌋ μ ( p ) ∑ l = 1 n l ∑ 1 ≤ k 1 < k 2 < ⋯ < k l ≤ n ∏ i = 1 l [ ( d ⋅ p ) ∣ a k i ] \begin{aligned} &\sum_{d = 2}^{m}\sum_{l = 1}^{n} d\cdot l\sum_{p = 1}^{\left\lfloor \frac{m}{d} \right\rfloor} \mu(p)\sum_{1 \leq k_1 < k_2 < \cdots < k_l \leq n} \prod_{i = 1}^{l}[(d\cdot p) | a_{k_i}] \\ =&\sum_{d = 2}^{m} d \sum_{p = 1}^{\left\lfloor \frac{m}{d} \right\rfloor} \mu(p) \sum_{l = 1}^{n} l \sum_{1 \leq k_1 < k_2 < \cdots < k_l \leq n} \prod_{i = 1}^{l}[(d\cdot p) | a_{k_i}]\end{aligned} =d=2ml=1ndlp=1dmμ(p)1k1<k2<<klni=1l[(dp)aki]d=2mdp=1dmμ(p)l=1nl1k1<k2<<klni=1l[(dp)aki] 记录原数组中 d ⋅ p d\cdot p dp 倍数的数量 c d ⋅ p c_{d\cdot p} cdp,然后 ∑ l = 1 n l ∑ 1 ≤ k 1 < k 2 < ⋯ < k l ≤ n ∏ i = 1 l [ ( d ⋅ p ) ∣ a k i ] = ∑ l = 1 c d ⋅ p l ( c d ⋅ p l ) \begin{aligned} \sum_{l = 1}^{n} l \sum_{1 \leq k_1 < k_2 < \cdots < k_l \leq n} \prod_{i = 1}^{l}[(d\cdot p) | a_{k_i}] = \sum_{l = 1}^{c_{d \cdot p}} l\binom{c_{d\cdot p}}{l}\end{aligned} l=1nl1k1<k2<<klni=1l[(dp)aki]=l=1cdpl(lcdp)

f ( n ) = ∑ i = 1 n i ( n i ) f(n) = \sum_{i = 1}^{n} i\binom{n}{i} f(n)=i=1ni(in),由于 ( n i ) = ( n − 1 i − 1 ) + ( n − 1 i ) \binom{n}{i} = \binom{n - 1}{i - 1} + \binom{n - 1}{i} (in)=(i1n1)+(in1),所以 f ( n ) = ∑ i = 1 n i ( n i ) = ∑ i = 1 n i ( n − 1 i − 1 ) + ∑ i = 1 n i ( n − 1 i ) = ∑ i = 0 n − 1 ( n − 1 i ) + 2 f ( n − 1 ) = 2 f ( n − 1 ) + 2 n − 1 \begin{aligned}f(n) = &\sum_{i = 1}^{n} i\binom{n}{i} \\ =&\sum_{i = 1}^n i \binom{n - 1}{i - 1} + \sum_{i = 1}^n i\binom{n - 1}{i} \\ =&\sum_{i = 0}^{n - 1}\binom{n - 1}{i} + 2f(n - 1) \\ = &2f(n - 1) + 2^{n - 1}\end{aligned} f(n)====i=1ni(in)i=1ni(i1n1)+i=1ni(in1)i=0n1(in1)+2f(n1)2f(n1)+2n1 能够线性递推。
预处理 f , c f, c f,c 等套式子计算即可,时间复杂度 O ( m ln ⁡ m ) O(m \ln m) O(mlnm)

代码

#include <bits/stdc++.h>

typedef long long LL;

const int MAXN = 200000;
const int MAXM = 1000000;
const int MOD = 1000000007;

inline int Add(const int &x, const int &y) {
    return (x + y >= MOD) ? (x + y - MOD) : (x + y);
}

inline int Mul(const int &x, const int &y) {
    return (LL)x * y % MOD;
}

inline int Sub(const int &x, const int &y) {
    return (x - y < 0) ? (x - y + MOD) : (x - y);
}

int Pow(int x, int y) {
    int ret = 1;
    while (y) {
        if (y & 1)
            ret = Mul(ret, x);
        y >>= 1;
        x = Mul(x, x);
    }
    return ret;
}

int N, M;
int A[MAXN + 5];
int Cnt[MAXM + 5], Num[MAXN + 5];

int Mu[MAXM + 5];
bool Vis[MAXM + 5];
std::vector<int> Primes;

void Init(int n) {
	Mu[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!Vis[i])
			Mu[i] = Sub(0, 1), Primes.push_back(i);
		for (int j = 0; j < (int)Primes.size() && i * Primes[j] < n; j++) {
			Vis[i * Primes[j]] = true;
			if (i % Primes[j] == 0) {
				Mu[i * Primes[j]] = 0;
				break;
			}
			Mu[i * Primes[j]] = Sub(0, Mu[i]);
		}
	}
}

int main() {
    Init(MAXM);
    scanf("%d", &N);
    for (int i = 1; i <= N; i++) {
        scanf("%d", &A[i]);
        Cnt[A[i]]++, M = std::max(M, A[i]);
    }
    for (int i = 1; i <= M; i++)
        for (int j = i + i; j <= M; j += i)
            Cnt[i] = Add(Cnt[i], Cnt[j]);
    for (int i = 1; i <= N; i++)
        Num[i] = Add(Add(Num[i - 1], Num[i - 1]), Pow(2, i - 1));
    int Ans = 0;
    for (int i = 2; i <= M; i++) {
        int cur = 0;
        for (int j = 1; j <= M / i; j++)
            cur = Add(cur, Mul(Mu[j], Num[Cnt[i * j]]));
        Ans = Add(Ans, Mul(i, cur));
    }
    printf("%d", Ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值