2020 Multi-University Training Contest 7

概要

01 02 03 04 05 06 07 08 09 10 11
总体 ? ? ?
wzgy ? ?
csz
wh ?

比赛地址

2020 Multi-University Training Contest 7

1008. Heart

题目大意:

n 个法术,每种法术需要一个物品的集合,每个物品只能被使用一次;一个可同时使用的法术的集合的权值为各法术权值的乘积。
q 次询问,问恰好使用物品集合为 x 的所有法术集合的权值和。

解题思路:

如果规定每个物品集合至多有两个法术,就是裸的子集卷积了。暴力做 21 次全子集卷积一定会超时。考虑优化:

由于最高位相同的法术不可能同时存在,即不可能卷积在一起,我们把物品按照最高位分组再分别卷积起来。

复杂度分析:O\left(\sum_{i=1}^{n}i^2\cdot 2^i \right)=O\left(i^n\cdot 2^n \right),且常数小于 2

#include <bits/stdc++.h>
using namespace std;
#define pct(x) __builtin_popcount(x)
const int P = 998244353;

void add(int &x, int y) {
    (x += y) >= P && (x -= P);
}
void sub(int &x, int y) {
    (x -= y) < 0 && (x += P);
}
void FWTor(vector<int> &a, bool rev) {
    int n = (int)a.size();
    for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {
        for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {
            if (!rev) add(a[i + j + m], a[i + j]);
            else sub(a[i + j + m], a[i + j]);
        }
    }
}

vector<int> Subset(vector<int> &a1, vector<int> &a2, int lim) {
    int n = 1 << lim;
    vector<int> ret(n);
    vector< vector<int> > a(lim + 1, vector<int>(n)), b = a, A = a;
    for (int i = 0; i < n; i++) {
        a[pct(i)][i] = a1[i]; b[pct(i)][i] = a2[i];
    }
    for (int i = 0; i <= lim; i++) {
        FWTor(a[i], false); FWTor(b[i], false);
    }
    for (int i = 0; i <= lim; i++) {
        for (int j = 0; j <= i; j++) {
            for (int k = 0; k < n; k++) {
                (A[i][k] += 1LL * a[j][k] * b[i - j][k] % P) %= P;
            }
        }
    }
    for (int i = 0; i <= lim; i++) FWTor(A[i], true);
    for (int i = 0; i < n; i++) ret[i] = A[pct(i)][i];
    return ret;
}
vector<int> conv(vector<int> &a) {
    int Base = 21, Len = 1 << Base;
    vector<int> ret(Len); ret[0] = 1;
    for (int n = 0; n < Base; n++) {
        int ful = 1 << n;
        auto A = vector<int>(ret.begin(), ret.begin() + ful);
        auto B = vector<int>(a.begin() + ful, a.begin() + ful * 2);
        auto C = Subset(A, B, n);
        for (int i = ful; i < ful * 2; i++) {
            ret[i] = C[i - ful];
        }
    }
    return ret;
}

int n, m;

int main(int argc, const char * argv[]) {
    scanf("%d", &n); int lim = 21;
    vector<int> a(1 << lim), ans;
    for (int i = 1, p, b; i <= n; i++) {
        scanf("%d%d", &p, &b);
        (a[b] += p) %= P;
    }
    ans = conv(a);
    scanf("%d", &m);
    for (int i = 1, x; i <= m; i++) {
        scanf("%d", &x);
        printf("%d\n", ans[x]);
    }
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇