首页 > 其他分享 >「解题报告」UOJ310 黎明前的巧克力

「解题报告」UOJ310 黎明前的巧克力

时间:2023-04-21 18:11:23浏览次数:53  
标签:黎明前 UOJ310 int 幂级数 异或 解题 MAXN ans FWT

我还是太不懂 FWT 了!

首先发现,两个人的集合异或和相等,那么这两个人的集合的并的异或和等于 \(0\),而相对应地,每一个大小为 \(k\) 的异或和为 \(0\) 的集合都有 \(2^k\) 种方案。那么我们实际上就是要找所有异或和等于 \(0\) 的方案数。

考虑集合幂级数刻画,那么我们要求的就是 \(n\) 个集合幂级数的异或卷积,即 \(\prod (1 + 2x^{\{a_i\}})\)。

显然不能直接求。观察单个式子的 FWT 结果,发现每个位置的值只有 \(\{-1, 3\}\) 两种情况。原因是因为 \(1\) 会使得每个数加 \(1\),\(2\) 会使得每个数 \(\pm 2\)。但是具体考虑每个位置究竟是加 \(3\) 还是减 \(3\) 仍然不好考虑。然后我就不会做了。

这时候有一个神奇的做法:我们可以直接求出来所有幂级数的 FWT 的和,然后由于我们知道每个位置的值只有 \(\{-1, 3\}\) 两种情况,所以我们是可以求出来有多少个 \(-1\) 与多少个 \(3\) 的。所以直接把所有幂级数加起来,然后一起 FWT,然后求出来分别有多少,快速幂得到点值然后再 IFWT 回去就能得到答案了。

为什么幂级数和的 FWT 等于幂级数 FWT 的和:FWT 是一个线性变换,所以显然。

一开始我想的是类似于 [省选联考 2022] 卡牌 的做法求出每个点值有多少个 \(3\),但是异或 FWT 的式子并不是很优美,完全无法直接求,不像那个题可以直接求前缀和。那么是不是那个题也可以这么做啊。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1048580, P = 998244353;
const int INV2 = (P + 1) / 2;
int qpow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
int n, a[MAXN];
int b[MAXN], c[MAXN];
void fwt(int limit, int a[], bool rev) {
    for (int mid = 1; mid < limit; mid <<= 1) {
        for (int l = 0; l < limit; l += (mid << 1)) {
            for (int i = 0; i < mid; i++) {
                int x = a[l + i], y = a[l + i + mid];
                a[l + i] = (x + y) % P, a[l + i + mid] = (x - y + P) % P;
                if (rev) {
                    a[l + i] = 1ll * a[l + i] * INV2 % P;
                    a[l + i + mid] = 1ll * a[l + i + mid] * INV2 % P;
                }
            }
        }
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        b[0]++;
        b[a[i]] += 2;
    }
    int limit = 1 << 20;
    fwt(limit, b, false);
    for (int i = 0; i < limit; i++) {
        int k = ((b[i] + n) % P) / 4;
        c[i] = qpow(3, k);
        if ((n - k) & 1) c[i] = (P - c[i]) % P;
    }
    fwt(limit, c, true);
    printf("%d\n", (c[0] - 1 + P) % P);
    return 0;
}

标签:黎明前,UOJ310,int,幂级数,异或,解题,MAXN,ans,FWT
From: https://www.cnblogs.com/apjifengc/p/17341344.html

相关文章

  • 2-207-通过(LeetCode-509)熟悉动态规划的解题步骤
    1.题目 运态规划的定义   动态规划的解题步骤  2.解法2.1递归 publicstaticintfibonacci(intn){if(n==0){return0;}if(n==1){return1;}returnfibonacci(n-1)+fibonacci(n-2);}2.2运态规划+递归......
  • ARC159解题报告
    比赛传送门A.CopyandPasteGraph题意:给定一个\(n\timesn\)的邻接矩阵,将其复制\(k^2\)遍(行和列各\(k\)个),得到一个\(nk\)个点的有向图。有\(q\)次询问,每次询问\(s\tot\)的最短路长度(或不可达)。\(n,q\le100,k\le10^9\)。考察一个点\(x\)在新图上能到达哪......
  • 「解题报告」CF1129D Isolation
    水题,但是调了好久qwq显然是DP,出现次数显然分块,那就数据结构优化DP呗。我们可以维护出当前点到每个点这段区间内有多少个出现次数为\(1\)的数,这个右端点每拓展一位修改的左端点一定是连续的区间。分块维护这个东西,如果是散块暴力重构暴力加,如果是整块那给整块打个加标记。......
  • CodeChef Starters 83 Division 1 解题报告
    CodeChefStarters83Division1题解\(\newcommand\v\mathrm\)\(\text{ByDaiRuiChen007}\)ContestLinkA.ConstructStringProblemLink题目大意给定长度为\(n\)的字符串\(S\),每次操作可以把三个相同的字符变成一个同样的字符(\(\texttt{ccc}\to\textttc\))求若......
  • 「解题报告」AGC001F Wide Swap
    首先题目给的限制条件很奇怪,下标差\(K\)而值域差\(1\)。我们变成逆排列,然后就转换成了下标差\(1\),值域差\(K\)了,每次操作就相当于交换相邻的两个差\(\geK\)的数。假设新的逆排列为\(Q_i\)。我们发现,假如存在两个数差\(<K\),那么它们的相对位置关系一定不变。那么我们现......
  • 4.14训练解题报告
    比赛传送门\(\color{white}20230413Tainrnig\)A.IceCave题意:考虑糖豆人的蜂窝迷图中的一层,走过一个正常格子就会变成洞。给定当前地板局面(抽象成\(n\timesm\)矩阵),以及起点和终点,求是否能在终点位置掉到下一层。特殊地,本题不允许停留。起点终点可以相同。\(n,m\le500\)......
  • 「解题报告」CF1528F AmShZ Farm
    之前zzy讲题讲到的,今天在题单里看到了,就又做了下。首先发现,对于一个\(a\)数组,\(b\)数组的方案数就是\(a\)中每个数的出现次数的\(k\)次方加和。考虑如何将\(a\)数组的条件转化一下。贪心的想,对于一个\(a_i\),我们肯定要尽可能使得它最终的数尽可能小。那么我们考虑每......
  • Codeforces Round #289 Div. 2 解题报告 A.B.C.E
    A-MaximuminTable纯递推。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>#include<set>#include<stdio.h>usingn......
  • Codeforces Round #290 (Div. 2) 解题报告 A.B.C.D.
    A-FoxAndSnake模拟。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>#include<set>#include<stdio.h>usingnames......
  • Codeforces Round #287 (Div. 2) 解题报告 A.B.C.D.E
    这次的CF挺水的,当时B题犯了一个很SB的错误,浪费了好多时间,所以D和E也没来得及看。sad,。。A-AmrandMusic水题,从小的开始选。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>......