CF1119H Triple/西行寺无余涅槃
Discription
现在有 个物品,同时有 种属性,每个属性有其价值
每个物品的一种属性对应一个权值
现在对于 中的每个 求出
Solution
“FWT 变换矩阵本来就是满秩的”
一种朴素的做法是求出每物品的每个属性所形成的集合幂级数暴力 并将点值乘起来再还原
看起来还原的一步是不可少的,那么尝试加速求点值的部分
直接求得的 的项数达到了 级别,那么尝试对其分类,最直接的方式就是使用 来表示点值系数的正负
更具体地,如果一个 的 中系数表示法下的 个位置向点值表示法下的第 位贡献为 ,使用一个长度为 的二进制数字表示 数组,其中 的位让 的第 为是
尝试对 中的每个 维护长度为 的数组 ,其中 表示对点值表示法下位置 贡献状态为 的物品的数量
那么如果求出了 个 ,容易得到每个状态的 对该点值处的贡献和,快速幂再乘积即可得到正确点值
问题转化为了求所有的 ,一种常用的手段是找等量关系来解方程,为了简化问题,下面的讨论都只考虑对 处的 来展开
尝试取出 的一个子集 ,设 ,写出其集合幂级数
这里的和式变换是因为 的过程中系数是统一的,也就是说 是线性变换,类似于可以使用一次函数进行 插值
我们考察 和 ,先看左边:
注意到
如果你不会证明
这个等量关系在 的时候按二进制位拆开考虑即可,因为位之间独立, 时讨论是 与否即可
在 的时候可以令 ,使用 的 RHS 把 LHS 两项缩成一项即可归到 的子问题
所以根据 的定义式子可以进行一些简单的和式变换:
第二行到第三行是发生了统计方式的转化:原来是逐物品枚举,同时将 包含的,给 点值有 贡献的 给予 贡献,而第三行不过是分类枚举,但是仍然强制在 集合内的 才能产生 贡献,因此根据实际含义找到了这样一组等量关系
事已至此,时间复杂度
Sample Code
const int N=1e5+10,MaxS=1<<16;
int n,m,k,w[10],tas[N][10],sw[100];
vector<int> c[MaxS];
signed main(){
n=read(); m=read(); k=read();
int U=1<<m;
vector<int> ans; ans.resize(U);
rep(i,1,k) w[i]=read();
rep(i,1,n) rep(j,1,k) tas[i][j]=read();
int S=1<<k;
for(int i=0;i<S;++i){
for(int j=1;j<=k;++j){
if(i>>(j-1)&1) ckdel(sw[i],w[j]);
else ckadd(sw[i],w[j]);
}
}
for(int i=0;i<U;++i) c[i].resize(S);
for(int i=0;i<S;++i){
vector<int> f; f.resize(U);
for(int j=1;j<=n;++j){
int xsum=0;
for(int e=1;e<=k;++e) if(i>>(e-1)&1){
xsum^=tas[j][e];
}
f[xsum]++;
}
FWT(f,U,1);
for(int j=0;j<U;++j) c[j][i]=f[j];
}
for(int i=0;i<U;++i){
FWT(c[i],S,-1);
ans[i]=1;
for(int j=0;j<S;++j) ckmul(ans[i],ksm(sw[j],c[i][j]));
}
FWT(ans,U,-1);
rep(i,0,U-1) print(ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律