【luogu CF1119H】Triple(FWT)

Triple

题目链接:luogu CF1119H

题目大意

给你 n 个数组,每个数组有 n 个数,其中有 x 个 ai,y 个 bi,z 个 ci。
x,y,z 是每个数组都一样,而 ai,bi,ci 每个数组不一样。
然后问你对于每个 i,从每个数组中选一个数,它们的异或和是 i 的情况有多少种。

思路

考虑弄一个类似每个数组的生成函数

uaivbiwci
uxai+vxbi+wxci

然后答案就是它们乘起来(FWT 异或乘)得到的数组。
但是不能一个一个乘,那我们考虑像某 巧克力 那道题一样,把它们加起来,然后乘,然后同两国解方程来得到每种情况的真实个数,然后得到真实的值。

然后因为你这样有 8 种情况,比较多,我们考虑小小的简化一下,第 i 个数组的大小都异或上 ai,然后就只有 4 种情况,然后答案的位置异或上所有 ai 的异或和即可。
ai1,bibiai,ciai
u+vxbi+wxci

一个位置 i,四个可能:
u+v+w 个数 n1
u+vw 个数 n2
uv+w 个数 n3
uvw 个数 n4

那我们考虑能不能用什么方法解方程之类的解出它们四个。
首先第一个式子显然四个 ni 的和是 n
那我们考虑只看 v 的正负(就是不管 u,w 是啥,亦或者当做 0
那这就是一个普通的 FWT,可以得到 y1
那同理我们只看 w 的正负,就可以得到 y2

还差一个,那我们考虑能不能考虑 v,w 同时做一个贡献。
那就是 bici 的位置是 1,其它的位置是 0,其实就是上面的两个式子卷积起来。
然后这么搞可以得到一个 y3,那式子就齐了。

{n1+n2+n3+n4=nn1+n2n3n4=y1n1n2+n3n4=y2n1n2n3+n4=y3

{n1=(n+y1+y2+y3)/4n2=(n+y12n1)/2n3=(n+y22n1)/2n4=(n+y32n1)/2

然后这题就可以做了,不难看出对于这种题有一个模型。
就是你通过每个位置是否贡献都做一次 FWT,得到方程的常数项(一共有 2k 种,正好对应 2k 个可能),然后你可以高消或者自己暴力解出方程,再带回去,IFWT。

代码

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define mo 998244353 using namespace std; const int N = (1 << 17); int n, k, all; ll f[N], f1[N], f2[N], f3[N], u, v, w; ll ksm(ll x, ll y) { ll re = 1; while (y) { if (y & 1) re = re * x % mo; x = x * x % mo; y >>= 1; } return re; } void FWT(ll *f, ll op, int n) { for (int mid = 1; mid < n; mid <<= 1) for (int R = mid << 1, j = 0; j < n; j += R) for (int k = 0; k < mid; k++) { ll x = f[j | k], y = f[j | mid | k]; f[j | k] = (x + y) % mo * op % mo; f[j | mid | k] = (x - y + mo) % mo * op % mo; } } int main() { scanf("%d %d", &n, &k); scanf("%lld %lld %lld", &u, &v, &w); for (int i = 1; i <= n; i++) { int a, b, c; scanf("%d %d %d", &a, &b, &c); b ^= a; c ^= a; all ^= a; f1[b]++; f2[c]++; f3[b ^ c]++; } FWT(f1, 1, 1 << k); FWT(f2, 1, 1 << k); FWT(f3, 1, 1 << k); ll inv4 = ksm(4, mo - 2), inv2 = ksm(2, mo - 2); for (int i = 0; i < 1 << k; i++) { ll n1 = (n + f1[i] + f2[i] + f3[i]) % mo * inv4 % mo; ll n2 = (n + f1[i] - 2 * n1 + 2 * mo) % mo * inv2 % mo; ll n3 = (n + f2[i] - 2 * n1 + 2 * mo) % mo * inv2 % mo; ll n4 = (n + f3[i] - 2 * n1 + 2 * mo) % mo * inv2 % mo; f[i] = ksm((u + v + w) % mo, n1) * ksm((u + v - w + mo) % mo, n2) % mo * ksm((u - v + w + mo) % mo, n3) % mo * ksm((u - v - w + 2 * mo) % mo, n4) % mo; } FWT(f, (mo + 1) / 2, 1 << k); for (int i = 0; i < 1 << k; i++) printf("%lld ", f[i ^ all]); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1119H.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示