2024CCPC济南 F. The Hermit

F. The Hermit

赛时不会。

首先,对于一个 $gcd=mn $ 的子集,一定是 g , λ 1 g , λ 2 g , ⋯ g,\lambda_1 g,\lambda_2g,\cdots g,λ1g,λ2g, 的形式,其中 λ i ∈ Z ∗ \lambda_i \in Z^{*} λiZ , λ i + 1 > λ i \lambda_{i+1} > \lambda_i λi+1>λi 。并且对这个子集删除元素一定要从开头开始删除,因为后边元素无论怎么删都不会改变局面。

我们首先拿到总贡献,就是 n × ( m n ) n\times{ m \choose n} n×(nm) 。然后考虑每个元素 x ∈ [ 1 , m ] x\in[1,m] x[1,m] 被删除多少次。

考虑 x x x 位于子集 ⋯ x ⋯ \cdots x\cdots x 中。

对于左边,设 f i , x f_{i,x} fi,x 表示长度为 i i i 的以 x x x 结尾的形如 x , 2 x , 6 x , 18 x x ,2x,6x,18x x,2x,6x,18x 之类的数组,一般形式满足每个元素是上一个元素的倍数,且结尾是 x x x ,注意 x x x 是随着长度倍增的,所以这个 f f f 的总状态很有限。

我们处理出来所有 f i , x f_{i,x} fi,x , 然后考虑 x x x 后面的所有元素,这些元素只需要是 x x x 的倍数即可,方案数一共 ( ⌊ m x ⌋ − 1 n − i ) {\lfloor \frac m x \rfloor}-1 \choose n-i (nixm1) 个。

答案就是 ∏ f i , x ( ⌊ m x ⌋ − 1 n − i ) \prod f_{i,x}{{\lfloor \frac m x \rfloor}-1 \choose n-i} fi,x(nixm1)

复杂度 ≤ O ( n log ⁡ n ) \leq O(n\log n) O(nlogn) ,加上一个 umap 的常数。

void solve(){
    fact[0] = 1;
    for(int i = 1; i < N; i ++){
        fact[i] = fact[i - 1] * i % mod;
    }
    infact[N - 1] = ksm(fact[N - 1], mod - 2);
    for(int i = N - 2; i >= 0; i --){
        infact[i] = infact[i + 1] * (i + 1) % mod;
    }
    cin >> m >> n;
    auto C = [&] (int n, int m){
        if(m < 0 || m > n) return 0LL;
        return fact[n] * infact[m] % mod * infact[n - m] % mod;
    };
    
    for(int x = 1; x <= m; x ++){
        f[1][x] = 1;
    }
    int res = n * C(m, n) % mod;
    for(int i = 1; i <= n; i ++){
        for(auto &[x, y] : f[i]){
            res = res - f[i][x] * C(m / x - 1, n - i) % mod;
            res %= mod;
            if(res < 0) res += mod;
            // f[i][x] = y;
            for(int j = 2; j * x <= m && i + 1 <= n; j ++){
                (f[i + 1][j * x] += f[i][x]) %= mod;
            }
        }
    }
    cout << res << '\n';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值