AtCoder Regular Contest 116 解题报告

本文同步发表在 hexo 博客

ARC116A - Odd vs Even

给定 T T T T ≤ 2 × 1 0 5 T\le 2\times 10^5 T2×105)个正整数 n n n 1 ≤ n ≤ 1 0 18 1\le n\le 10^{18} 1n1018),问 n n n 的奇约数多还是偶约数多。(约数均为正约数)

很明显,如果 n   m o d   2 = 1 n\bmod 2 = 1 nmod2=1,则答案为奇约数多。

否则考察约数们怎么来的。对于一个偶数 n n n 我们总能将其这样拆分: n = 2 k × p n = 2^k\times p n=2k×p p p p 为奇数)。那么如果 k = 1 k = 1 k=1,则不难发现奇偶约数一样多,否则肯定是偶约数多。

ARC116B - Products of Min-Max

给定一含正整数的集合 A A A,求
∑ S ⊆ A max ⁡ a ∈ S { a } min ⁡ a ∈ S { a }   m o d   998244353 \sum_{S\subseteq A}\max_{a\in S}\lbrace a\rbrace\min_{a\in S}\lbrace a\rbrace\bmod{998244353} SAaSmax{a}aSmin{a}mod998244353
的值。

比较妙的题。

首先考虑把最大值和最小值拎出来考虑贡献:将其 A A A 从小到大排序。

然后假设此时 i < j i<j i<j,则 a i ≤ a j a_i\le a_j aiaj,这一对元素贡献的子集个数为 2 j − i − 1 2^{j - i - 1} 2ji1。所以答案就为
∑ i = 1 n − 1 ∑ j = i + 1 n a i a j ⋅ 2 j − i + ∑ i = 1 n a i 2 \sum_{i = 1}^{n - 1}\sum_{j = i + 1}^na_ia_j\cdot2^{j - i} + \sum_{i = 1}^na_i^2 i=1n1j=i+1naiaj2ji+i=1nai2
化简下来可以得到
∑ i = 1 n − 1 ( a i ⋅ 2 − i ∑ j = i + 1 n a j ⋅ 2 j − 1 ) + ∑ i = 1 n a i 2 \sum_{i = 1}^{n - 1}\left(a_i\cdot 2^{-i}\sum_{j = i + 1}^na_j\cdot2^{j - 1}\right) + \sum_{i = 1}^na_i^2 i=1n1(ai2ij=i+1naj2j1)+i=1nai2
预处理 a i 2 i − 1 a_i2^{i - 1} ai2i1 的后缀和就可以直接做了,复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <cstdio>
#include <cctype>
#include <algorithm>
#define FOR(i, a, b) for (int i = a; i <= b; ++i)
#define DEC(i, a, b) for (int i = a; i >= b; --i)

typedef long long ll;

ll read()
{
    ll s = 0, x = 0;
    char c = getchar();
    while (!isdigit(c))
        x |= (c == '-'), c = getchar();
    while (isdigit(c))
        s = s * 10 + c - '0', c = getchar();
    return x ? -s : s;
}

const ll mod = 998244353;
const int maxn = 2e5 + 5;

int n;
ll a[maxn], pow2[maxn], s[maxn];

ll inv(ll a)
{
    ll b = mod - 2, ret = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1) ret = ret * a % mod;
    return ret;
}

int main()
{
    n = read();
    pow2[0] = 1;
    FOR(i, 1, n) a[i] = read(), pow2[i] = pow2[i - 1] * 2 % mod;
    std::sort(a + 1, a + n + 1);
    DEC(i, n, 1) s[i] = (s[i + 1] + pow2[i - 1] * a[i] % mod) % mod;
    ll ans = 0;
    FOR(i, 1, n - 1)
        ans = (ans + inv(pow2[i]) * a[i] % mod * s[i + 1] % mod) % mod;
    FOR(i, 1, n) ans = (ans + a[i] * a[i] % mod) % mod;
    printf("%lld\n", ans);
    return 0;
}

ARC116C - Multiple Sequences

给定 n n n m m m 1 ≤ n , m ≤ 2 × 1 0 5 1\le n,m\le 2\times 10^5 1n,m2×105),求满足下列条件的长度为 n n n 的整数序列 A A A 的个数。

  • 1 ≤ A i ≤ m 1\le A_i\le m 1Aim
  • A i + 1 A_{i + 1} Ai+1 A i A_i Ai 的整数倍

结果模 998244353 998244353 998244353

很妙的计数题。

考虑从 1 1 1 m m m 枚举 A n A_n An 的值。我们可以发现其就是把 A n A_n An 每个质因子给安排在 n n n 个不同的位置上,求方案数。但是此时需要对每个质因子分开考虑,假设 A n = ∏ p i c i A_n = \prod p_i^{c_i} An=pici,则我们需要对每个质因子都用插板法然后再乘起来得到总方案,即
f ( A n ) = ∏ ( n + c i − 1 c i ) f(A_n) = \prod\binom{n + c_i - 1}{c_i} f(An)=(cin+ci1)
最后把所有的结果加起来即为答案。

#include <cstdio>
#include <cctype>
#include <vector>
#define FOR(i, a, b) for (int i = a; i <= b; ++i)
#define DEC(i, a, b) for (int i = a; i >= b; --i)

const int maxn = 3e5 + 5, mod = 998244353;

int read()
{
    int s = 0, x = 0;
    char c = getchar();
    while (!isdigit(c))
        x |= (c == '-'), c = getchar();
    while (isdigit(c))
        s = s * 10 + c - '0', c = getchar();
    return x ? -s : s;
}

typedef long long ll;

ll n, m;

ll qpow(ll a)
{
    ll b = mod - 2, ret = 1;
    for (; b; b >>= 1, a = 1ll * a * a % mod)
        if (b & 1) ret = 1ll * ret * a % mod;
    return ret;
}

ll fact[maxn], inv[maxn];

ll binom(int n, int k)
{
    return fact[n] * inv[k] % mod * inv[n - k] % mod;
}

void init()
{
    fact[0] = 1;
    FOR(i, 1, maxn - 1) fact[i] = i * fact[i - 1] % mod;
    inv[maxn - 1] = qpow(fact[maxn - 1]);
    DEC(i, maxn - 2, 0) inv[i] = (i + 1) * inv[i + 1] % mod;
    return;
}

int main()
{
    n = read(), m = read();
    init();
    ll ans = 0;
    FOR(i, 1, m)
    {
        int now = i;
        std::vector<int> tmp;
        for (int p = 2; p * p <= now && now != 1; ++p)
        {
            if (now % p) continue;
            int cnt = 0;
            while (now % p == 0)
                ++cnt, now /= p;
            tmp.push_back(cnt);
        }
        if (now != 1) tmp.push_back(1);
        ll t = 1;
        for (auto c : tmp)
            t = t * binom(n + c - 1, c) % mod;
        ans = (ans + t) % mod;
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值