The 2024 ICPC Asia East Continent Online Contest (II) K.Match
题面
给定长度为 \(n\) 的两个序列 \(a\) 和 \(b\),当且仅当 \(a_i ⊕ b_j ≥ k\) 时,\(a_i\) 与 \(b_j\) 连一条双向边,其中 \(⊕\) 表示 XOR 运算。对于 \([1, n]\) 范围内的每个 \(x\),计算大小为 \(x\) 的匹配数的个数,结果对 \(998244353\) 取模。
题解
考虑两个序列 \(A, B\) 如何计算,不妨考虑从 \(k\) 的最高位开始枚举,对于 \(k\) 的下一个位,当前的合法 \(A, B\) 一定,我们为了方便讨论,按当前位为 \(0/1\) 分为 \(A_0, A_1, B_0, B_1\)。
序列 \(A_0, A_1, B_0, B_1\) 的大小是单调不增的,为了方便讨论,我们规定 \(|S|\) 表示集合 \(S\) 的大小,\(\leftrightarrow\) 表示两者有边。
\(k\) 的下一位为 \(1\),序列 \(A, B\) 合法的条件是 \(A_0 \leftrightarrow B_1\) 和 \(A_1 \leftrightarrow B_0\)。
- 记 \(A_0 \leftrightarrow B_1\) 的方案数为 \(f_i\),\(A_1 \leftrightarrow B_0\) 的方案数为 \(g_i\),容易发现,答案为 \(f\) 与 \(g\) 的一个卷积,即 \(ans_{i + j} = f_i \times g_j\)。
\(k\) 的下一位为 \(0\),序列 \(A, B\) 的合法条件为 \(A_0 \leftrightarrow B_0\) 和 \(A_1 \leftrightarrow B_1\),同时对于 \(A_0 \leftrightarrow B_1\) 和 \(A_1 \leftrightarrow B_0\) 一定成立,我们需要考虑如何将两者答案合并。
记 \(A_0 \leftrightarrow B_0\) 的方案数为 \(f_i\),\(A_1 \leftrightarrow B_1\) 的方案数为 \(g_i\),\(A_0 \leftrightarrow B_1\) 的方案数为 \(h_i\),\(A_1 \leftrightarrow B_0\) 的方案数为 \(t_i\)。
考虑 \(A_0 \leftrightarrow B_1\) 和 \(A_1 \leftrightarrow B_0\) 的任选性,任选 \(i\) 个对其随机排列,容易看出 \(h_i = i!\binom{|A_0|}{i}\binom{|B_1|}{i}\),\(t_i = i!\binom{|A_1|}{i}\binom{|B_0|}{i}\)。
\(A_0 \leftrightarrow B_0\) 和 \(A_1 \leftrightarrow B_1\) 的组合意义同 \(k\) 取 \(1\) 时的操作,对 \(f\) 与 \(g\) 做卷积得到 \(S_{i+j} = f_i \times g_j\)。
为了将 \(h, t\) 与 \(S\) 合并,枚举三个集合分别选择了 \(i, j, l\) 个匹配。
对每组 \((i, j)\),去除 \(A_0 \leftrightarrow B_0\) 使用的 \(i\) 对,\(A_1 \leftrightarrow B_1\) 使用的 \(j\) 对,每次重新计算一组 \(S\),其中 \(h_u = u!\binom{|A_0| - i}{u}\binom{|B_1| - j}{u}\),\(t_u = u!\binom{|A_1| - j}{u}\binom{|B_0| - i}{u}\)
先卷 \(h\) 和 \(t\) 得到 \(S\),再把三者卷起来有 \(ans_{i + j + l} = h_i \times t_j \times S_l\)。
考虑边界情况,定义 \(\operatorname{solve(A, B, lev)}\) 为递归计算的 \(A, B\) 序列,\(lev\) 为当前考虑的位。
当 \(|A| = 0\) 或 \(|B| = 0\) 时,没有可选项数,\(ans_0 = 1\),\(ans_i = 0(i > 0)\)。
当 \(lev = -1\) 时,说明前面的位被考虑完毕了,\(A, B\) 可以任意组合,计算 \(ans_i = i!\binom{|A|}{i}\binom{|B|}{i}\)。
否则将 \(A, B\) 按当前位分解为 \(A_0, A_1, B_0, B_1\) 对下一个 \(lev\) 讨论。
按照题意分析复杂度,对于 \(k\) 的位为 \(0\) 时,计算一次 \(S\) 的复杂度是卷积 \(O(n^2)\) 的,卷一次 \(ans_{i + j + l}\) 需要枚举 \(i, j\),并在当前 \(i, j\) 下卷出一个 \(S\),时间复杂度是 \(O(n^4)\) 的,可以优化做到 \(O(n^3\log{n})\),但是原算法时间复杂度很小,因为 \(|A|, |B|\) 的大小是单调不增的,所以跑不满。
总体时间复杂度 \(O(n^4\log{k})\),代码如下。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> Poly;
const int N = 405, mod = 998244353, maxn = 400;
ll n, k;
ll frac[N], inv[N];
ll ksm(ll a, ll k)
{
ll res = 1;
while (k)
{
if (k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void init()
{
frac[0] = inv[0] = 1;
for (int i = 1; i <= maxn; i ++ ) frac[i] = frac[i - 1] * i % mod;
inv[maxn] = ksm(frac[maxn], mod - 2);
for (int i = maxn - 1; i; i -- ) inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll C(ll x, ll y)
{
if (x < y || y < 0) return 0;
return frac[x] * inv[y] % mod * inv[x - y] % mod;
}
Poly Covolution(Poly x, Poly y)
{
Poly tmp(x.size() + y.size() - 1);
for (int i = 0; i < x.size(); i ++ )
for (int j = 0; j < y.size(); j ++ )
(tmp[i + j] += x[i] * y[j]) %= mod;
return tmp;
}
Poly calc(int x, int y)
{
Poly tmp(min(x, y) + 1);
for (int i = 0; i <= min(x, y); i ++ ) tmp[i] = C(x, i) * C(y, i) % mod * frac[i] % mod;
return tmp;
}
Poly solve(Poly x, Poly y, int lev)
{
if (x.empty() || y.empty()) return Poly(1, 1);
if (lev == -1) return calc(x.size(), y.size());
Poly X[2], Y[2];
for (auto i : x) X[i >> lev & 1].push_back(i);
for (auto i : y) Y[i >> lev & 1].push_back(i);
if (k >> lev & 1) return Covolution(solve(X[1], Y[0], lev - 1), solve(X[0], Y[1], lev - 1));
Poly tmp[2], res(min(x.size(), y.size()) + 1);
tmp[0] = solve(X[0], Y[0], lev - 1), tmp[1] = solve(X[1], Y[1], lev - 1);
for (int i = 0; i < tmp[0].size(); i ++ )
for (int j = 0; j < tmp[1].size(); j ++ )
{
Poly c = Covolution(calc(X[0].size() - i, Y[1].size() - j), calc(X[1].size() - j, Y[0].size() - i));
for (int l = 0; l < c.size(); l ++ ) (res[i + j + l] += tmp[0][i] * tmp[1][j] % mod * c[l]) %= mod;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
init();
cin >> n >> k;
Poly a(n), b(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
for (int i = 0; i < n; i ++ ) cin >> b[i];
Poly ans = solve(a, b, 60);
ans.resize(n + 1);
for (int i = 1; i <= n; i ++ ) cout << ans[i] << "\n";
return 0;
}
The 2024 ICPC Asia East Continent Online Contest (II) K.Match的更多相关文章
- 训练20191009 2018-2019 ACM-ICPC, Asia East Continent Finals
2018-2019 ACM-ICPC, Asia East Continent Finals 总体情况 本次训练共3小时20分钟,通过题数4. 解题报告 D. Deja vu of - Go Play ...
- 2018-2019 ACM-ICPC, Asia East Continent Finals I. Misunderstood … Missing(dp)
题目链接: http://codeforces.com/gym/102056/problem/I 题意: 人物有l两个属性分别是$A,D$ 每个回合人物$A\pm D$ 每个回合有三个选择分别是: 1 ...
- 2018-2019 ACM-ICPC, Asia East Continent Finals部分题解
C:显然每p2个数会有一个0循环,其中22 32 52 72的循环会在200个数中出现,找到p2循环的位置就可以知道首位在模p2意义下是多少,并且循环位置几乎是唯一的(对72不满足但可能的位置也很少) ...
- 2018-2019 ACM-ICPC, Asia East Continent Finals Solution
D. Deja vu of … Go Players 签. #include <bits/stdc++.h> using namespace std; int t, n, m; int m ...
- 2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final 2017) Solution
A:Chat Group 题意:给出一个n, k 计算C(n, k) -> C(n,n) 的和 思路:k只有1e5 反过来想,用总的(2^ n) 减去 C(n, 0) -> C(n, k ...
- The 2017 ACM-ICPC Asia East Continent League Final记录
首先感谢tyz学弟的麻麻-给我们弄到了名额- 然后就开始了ACM ECLFinal的玩耍,A*仙人掌可是立了flag要好好打的- 试机赛好像就全是GCJ kickstart的原题,然后AK了但是由于一 ...
- Codeforces Gym 101775D Mr. Panda and Geometric Sequence(2017-2018 ACM-ICPC Asia East Continent League Final,D题,枚举剪枝)
题目链接 ECL-Final 2017 Problem D 题意 给定$2*10^{5}$组询问,每个询问求$l$到$r$之间有多少个符合条件的数 如果一个数小于等于$10^{15}$, 并且能被 ...
- 2019-2020 ICPC Asia Hong Kong Regional Contest
题解: https://files.cnblogs.com/files/clrs97/19HKEditorial-V1.zip Code:(Part) A. Axis of Symmetry #inc ...
- 2018-2019 ACM-ICPC, Asia East Continent Final L Eventual … Journey
#include<iostream> using namespace std; ; int cnt[MAX]; int ans[MAX]; int a[MAX]; int main() { ...
- 训练20191005 2017-2018 ACM-ICPC Asia East Continent League Final
A 签到 M 签到 K 读懂后签到 L 博弈论 [引理]出现SXXS结构时后手必胜. 很容易发现n为奇数时后手不可能胜利,n为偶数时先手不可能胜利.n≤6时一定平局,n≥7时先手有可能胜利,n≥16时 ...
随机推荐
- diff 输出解释
diff 最原始的 diff 我们先编写两个文件: f1: 1 2 3 4 5 6 7 8 9 f2: 1 2 3 4 5 66 7 8 9 然后我们进行比较: diff f1 f2 6c6 < ...
- AI驱动的PlantUML:快速生成专业级UML类图和用例图
承接前文关于如何运用 AI 工具生成时序图的内容[1],今天我们继续探讨 AI 驱动的 PlantUML:高效创建专业的 UML 类图与用例图. [1]: https://juejin.cn/post ...
- express项目的创建
前言 前端开发者若要进行后端开发,大多都会选择node.js,在node生态下是有大量框架的,其中最受新手喜爱的便是老牌的express.js,接下来我们就从零创建一个express项目. 安装nod ...
- Consul初探-从安装到运行 【转】
目录 前言 下载二进制包 入门必学必记文档 启动 Consul 前言 伟人说过:实践是检验真理的唯一标准!经过上一篇的学习,我基本掌握了 Consul 的基本原理,接下来就是动手实践了:Consul ...
- jstack排查cpu占用高的步骤
通过jstack排查cpu占用高的问题 1.通过top命令找到cpu占用高的应用程序进程 2.通过top -H -p pid查看该应用中占用CPU高的线程. 3.通过printf "%x\n ...
- PageHeper
PageHelper 是一个非常流行的 MyBatis 分页插件,主要用于简化分页查询的实现.使用 PageHelper 可以在执行数据库查询时,自动处理分页参数,从而避免手动编写繁琐的分页逻辑. 今 ...
- .NET 的 Native AOT 现在是什么样的?
今天要写的这篇文章源自昨天在朋友圈发的文章<UWP 通过 .NET 9 和Native AOT 的支持实现 UWP 应用的现代化>[1],一位小伙伴的对话让我想全面梳理下Native AO ...
- 项目发布后项目时间和linux时间不一致
查阅了很多资料,本来总以为是项目的问题,启动前端,连接不同的后台,本地项目时间是正确的,部署到linux Docker容器就不行.很纳闷...... 基于以上,还是决定记下来,以便后来的人查阅,解决问 ...
- [OI] 珂朵莉树
对于一个序列,它有较多重复元素,并且题目需要维护区间修改,维护区间信息,维护整块值域信息的,那么就可以考虑珂朵莉树解决. 主要思想 珂朵莉树将全部相同的颜色块压缩为一组,如对于下述序列: 1 1 1 ...
- HDK Include Header File (1.7)
Download 1.7 | 1.7.1 | 1.7.2 1.7.1 使用方法:编译选项->目录->C++包含文件->添加 [解压目录]\include 1.7.2 使用方法:编译选 ...