炼金术(Alchemy)

GitHub跳转原题关系图返回列表

把每种金属在 k 个熔炉中的出现情况看成一个长度为 k 的 0/1 模式,合法模式有 2^k-1 种,总答案是 (2^k-1)^n。

OJ: luogu

题目 ID: P8557

难度:普及/提高-

标签:数学容斥快速幂思维

日期: 2026-06-20 06:57

题意

k 个熔炉,每个熔炉会炼出 n 种金属中的某个子集,也可能什么都没有。

如果把所有熔炉炼出的金属合并起来,包含了全部 n 种金属,就算成功炼出合金。

要求统计有多少种炼制情况,答案对 998244353 取模。

思路

先看一个可以直接验证的小数据暴力:

cpp
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

int n, k;
int furnace_choose[20];
i64 ans = 0;

void dfs(int pos) {
    if (pos == k + 1) {
        int all_mask = 0;
        for (int i = 1; i <= k; i++) {
            all_mask |= furnace_choose[i];
        }

        if (all_mask == (1 << n) - 1) {
            ans++;
        }
        return;
    }

    for (int mask = 0; mask < (1 << n); mask++) {
        furnace_choose[pos] = mask;
        dfs(pos + 1);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> k;
    dfs(1);
    cout << ans % 998244353 << '\n';
    return 0;
}

暴力版直接枚举每个熔炉炼出哪个子集,最后把它们按位或起来,看能不能覆盖全部金属。

不按熔炉想,按金属想

如果按熔炉来想,每个熔炉都有 2^n 种选择,整体看起来很乱。
但如果反过来按“某一种金属”来想,事情会非常简单。

固定某一种金属,它在 k 个熔炉里会出现成一个长度为 k0/1 模式:

  • 某个熔炉产出这种金属:记 1
  • 没产出:记 0

这样的模式一共有:

  • 2^k

种。

但如果全是 0,说明这种金属一个熔炉都没炼出来,那最终就不可能合成合金。
所以对每一种金属来说,合法模式数是:

  • 2^k - 1

各种金属彼此独立

1 种金属在各熔炉里怎么出现,和第 2 种金属怎么出现,是互不影响的。
因此:

  • 每种金属各有 2^k - 1 种合法模式
  • 一共 n 种金属

直接用乘法原理得到答案:

  • (2^k - 1)^n

因为 nk 都很大,所以需要两次快速幂。

代码

cpp
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

const i64 MOD = 998244353;

i64 quick_pow(i64 base, i64 exp) {
    i64 ans = 1 % MOD;
    base %= MOD;

    while (exp > 0) {
        if (exp & 1) {
            ans = ans * base % MOD;
        }
        base = base * base % MOD;
        exp >>= 1;
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    i64 n, k;
    cin >> n >> k;

    i64 ways_for_one_metal = quick_pow(2, k) - 1;
    if (ways_for_one_metal < 0) {
        ways_for_one_metal += MOD;
    }

    cout << quick_pow(ways_for_one_metal, n) << '\n';
    return 0;
}

复杂度

两次快速幂:

  • 时间复杂度 O(logk+logn)O(log k + log n)
  • 空间复杂度 O(1)O(1)

总结

这题最关键的转换是:

  • 不按熔炉枚举子集
  • 改成按每种金属在 k 个熔炉中的出现模式计数

一旦切换视角,答案就直接变成:

  • (2^k - 1)^n