题解 CF1713F Lost Array
第一步是如果给定 ,怎么求 的最后一列。
考虑到 ,那么我们考虑最终 的贡献:对于每个 ,设 有 种不同走法(每一步向右或向下走,第一步必须向下)能到达 ,那么 对 的贡献有 次。由于是异或, 是奇数贡献为 ;否则为 。
考虑计算 到 有几种走法,运用组合数容易得到走法数为 。这个形式比较难受,我们考虑反转 ,并且 下标都从 开始,式子变成了 。根据 Lucas 定理(即 [CTSC2017]吉夫特 的经典结论),这个式子有贡献当且仅当 ,也容易转化为 。
将下标设成从 开始并反转 后,我们得到由 推出 的式子:。我们可以用 FWT 或 FMT 在 的时间内由 计算出 ,但这不是本题要求。
本题中已知 求 ,我们根据子集反演式子:
由于运算是异或,那么不用考虑 的系数,也就是说对于一个数组 做一遍 FMT 得到 ,那么也可以从 做一遍完全一致的 FMT 得到 。
遗憾的是本题还没有做完。你发现把 转化成子集形式后, 数组的前几项未知,那么你也不能做反着的 FMT 从 推出 。我场上也就到这里就止步了,所以没有做出此题。
不妨换一个思路。定义 是 做一遍后缀 FMT 的结果,即 为所有 的超集 的异或和。考虑 是 的所有位 都不能存在。我们容斥,枚举 的子集 ,钦定这 位需要选,其他位随意,那么要计算的是满足 是 的子集的所有 (也就是 ),原本 的容斥系数由于是异或也不需要考虑。
所以从 推 得出了一个新的做法:先对 每个位置变成其超集的异或和,记这个新数组为 ,再对 每个位置变成其子集的异或和,就可以得到 。
这个做法不会存在前一个做法“数组的前几项未知”的问题,因此从 反着做两个 FMT 回去就行了。
#include <bits/stdc++.h>
using namespace std;
int n,a[1000005];
int main()
{
cin >> n;
for (int i=0;i<n;i++) cin >> a[i];
for (int i=0;i<19;i++)
{
for (int j=0;j<n;j++)
{
if (j&(1<<i)) a[j]^=a[j^(1<<i)];
}
}
for (int i=0;i<19;i++)
{
for (int j=0;j<n;j++)
{
if (j&(1<<i)) a[j^(1<<i)]^=a[j];
}
}
for (int i=n-1;i>=0;i--) cout << a[i] << " ";
return 0;
}
小声:看官方题解不是很懂,特别感谢神仙 @chenxinyang2006 的指点,让我受益匪浅。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?