CF1034E Little C Loves 3 III

CF1034E Little C Loves 3 III

FWT, 构造

子集卷积 + 很小的模数?

但朴素的子集卷积时间空间都过不了

考虑到有个小模数

\(A_i = a_i4^{|i|}, B_i= b_i4^{|i|}\)

发现 \(C_k = \sum\limits_{i|j = k} A_iB_j = a_ib_j4^{|i| + |j|}\),这里的 \(|i| + |j| \ge |k|\) ,而题目要求的 \(|i| + |j| = |k|\)

其实 \(c_i = \frac {C_i}{4^{|i|}} \mod 4\)

证明:

因为对于 \(|i| + |j| > |k|\)\(C_k\) , 必定是 \(4^{|k|}\) 的倍数 , 所以除以 \(4^{|k|}\) 就相当于对 \(4\) 取模 , 不影响结果

而对于 \(|i| + |j| = |k|\)\(C_k\) ,除以 \(4^{|k|}\) 就相当于还原

所以对 \(A, B\) 做 FWT ,最终答案除以 \(4^{|i|}\) 就行了

#include <bits/stdc++.h>
#define re register
#define int unsigned long long
// #define pair pair<int, int>
// #define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout);
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
using namespace std;
inline int read()
{
    re int x = 0, f = 0;
    re char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
    while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
    return f ? -x : x;
}
inline string getstr()
{
    string res = "";
    re char ch = getchar();
    while (isspace(ch)) ch = getchar();
    while (!isspace(ch)) res.push_back(ch), ch = getchar();
    return res;
}
const int N = (1 << 21) + 6, P = 998244353, M = 1e4 + 4;
void FWT(int *A, const int &siz, const int &flag)
{
    for (re int len = 1; len < siz; len <<= 1)
    {
        const int rlen = len << 1;
        for (re int i = 0; i < siz; i += rlen)
            for (re int j = 0; j < len; ++j)
            {
                int x = A[i + j], y = A[i + j + len];
                A[i + j] = x;
                A[i + j + len] = y + x * (flag ? -1ll : 1ll);
            }
    }
}
int a[N], b[N], mi[N];
#define cnt(i) __builtin_popcount(i)
signed main()
{
    int n = read(), siz = 1 << n; mi[0] = 1;
    for (re int i = 1; i <= n; ++i) mi[i] = mi[i - 1] * 4ll;
    for (re int i = 0; i < siz; ++i) a[i] = (getchar() - 48) * mi[cnt(i)];
    getchar();
    for (re int i = 0; i < siz; ++i) b[i] = (getchar() - 48) * mi[cnt(i)];
    FWT(a, siz, 0), FWT(b, siz, 0);
    for (re int i = 0; i < siz; ++i) a[i] = a[i] * b[i];
    FWT(a, siz, 1);
    for (re int i = 0; i < siz; ++i) printf("%lld", a[i] / mi[cnt(i)] % 4);
    
    return 0;
}
posted @ 2022-01-23 16:58  After-glow  阅读(45)  评论(0)    收藏  举报