当前位置: 首页 > news >正文

[NOI2025] 集合 题解

去不了 NOI 的菜鸡终于把集合看懂了,写个博客加深一下印象。
[NOI2025] 集合

要求:

\[ans=\sum_P \sum_Q [f(p)=f(Q)][P\cap Q = \emptyset] \prod_{i\in P\cup Q} a_i \]

先处理这题比较特殊的 \([f(p)=f(Q)]\),考虑枚举 \(f(P)=f(Q)=S\)\(f(P),f(Q)\) 恰好等于 \(S\) 不好做,容斥一下变成包含:

\[\begin{aligned} ans &= \sum_S \sum_{S\subseteq T_P} \sum_{S\subseteq T_Q} \sum_{T_P \subseteq f(P)} \sum_{T_Q \subseteq f(Q)} (-1)^{|T_P|-|S|} (-1)^{|T_Q|-|S|} [P\cap Q = \emptyset] \prod_{i\in P\cup Q} a_i\\&= \sum_S \sum_{S\subseteq T_P} \sum_{S\subseteq T_Q} \sum_{T_P \subseteq f(P)} \sum_{T_Q \subseteq f(Q)} (-1)^{|T_P|+|T_Q|-2|S|} [P\cap Q = \emptyset] \prod_{i\in P\cup Q} a_i\\ \end{aligned} \]

发现容斥系数上的 \(-2|S|\) 没有用,可以去掉,所以也就没有必要枚举 \(S\),只需要枚举 \(T_P,T_Q\) 然后乘上合法的 \(S\) 数量即可,而合法的 \(S\) 满足 \(S\subseteq T_P,T_Q\) 也即 \(S\subseteq T_P\cap T_Q\),所以合法的 \(S\) 数量为 \(2^{|T_P\cap T_Q|}\)。为了美观,下面用 \(S,T\) 分别代替 \(T_P,T_Q\)

\[\begin{aligned} ans &= \sum_{S} \sum_{T} (-1)^{|S|+|T|} 2^{|S\cap T|} \sum_{S \subseteq f(P)} \sum_{T \subseteq f(Q)} [P\cap Q = \emptyset] \prod_{i\in P\cup Q} a_i\\ \end{aligned} \]

\(S \subseteq f(P)\) 相当于什么,其实就是说 \(P\) 中的数都要是 \(S\) 的超集,我们设 \(R_S\)\(S\) 的超集构成的集合,则 \(P\subseteq R_S\),于是我们就把跟 \(f\) 有关的东西去掉了。
然后处理 \([P\cap Q = \emptyset]\),我们直接去枚举 \(R=P\cup Q\),显然 \(R\subseteq R_S\cup R_T\)。那么对于 \(i\in R\),若 \(i\) 只属于 \(R_S\)\(R_T\) 中的一个,则 \(i\) 只能放到那一个,否则 \(i\) 放到哪一个都可以。

\[\begin{aligned} ans &= \sum_{S} \sum_{T} (-1)^{|S|+|T|} 2^{|S\cap T|} \sum_{R\subseteq R_S\cup R_T} \prod_{i\in R} (1+[i\in R_S\cap R_T])a_i\\&= \sum_{S} \sum_{T} (-1)^{|S|+|T|} 2^{|S\cap T|} (\prod_{i\in R_S\cup R_T \setminus R_S\cap R_T} (a_i+1)) (\prod_{i\in R_S\cap R_T} (2a_i+1))\\ \end{aligned} \]

\(f_S=\prod_{i\in R_S} (a_i+1),g_S=\prod_{i\in R_S} (2a_i+1)\),这两个可以高维后缀积 \(O(n2^n)\) 预处理。又发现 \(R_S\cap R_T=R_{S\cup T}\)

\[ans = \sum_{S} \sum_{T} (-1)^{|S|+|T|} 2^{|S\cap T|} f(S)f(T)\dfrac{g(S\cup T)}{f(S\cup T)^2} \]

然后这里有个问题是分母可能为 \(0\),有一个 trick 是直接把每个数用 \(x\times 0^k\) 的形式存储,表示这个数里面目前有 \(k\)\(0\),然后就可以做除法了。
发现这个式子里同时有 \(S\cap T\)\(S\cup T\),但是 \(S\cap T\) 我们只关心他的大小,所以我们可以用 \(|S\cap T|=|S|+|T|-|S\cup T|\) 来换掉:

\[\begin{aligned} ans &= \sum_{S} \sum_{T} (-1)^{|S|+|T|} 2^{|S|+|T|-|S\cup T|} f(S)f(T)\dfrac{g(S\cup T)}{f(S\cup T)^2} \\ &= \sum_{S} \sum_{T} (-2)^{|S|}f(S) \times (-2)^{|T|}f(T) \times \dfrac{g(S\cup T)}{2^{|S\cup T|}f(S\cup T)^2} \end{aligned} \]

\(F(S)=(-2)^{|S|}f(S),h=F\times F\),这里 \(\times\) 是或卷积,则:

\[ans=\sum_S \dfrac{h(S)g(S)}{2^{|S|}f(S)^2} \]

最后一个问题是,这里 \(F\) 是用 \(x\times 0^k\) 的形式存储,但是做 FMT 的时候涉及到加减法,当 \(k_1\ne k_2\) 时,两个数 \(x1\times 0^{k_1},x2\times 0^{k_2}\) 无法简单的加减法。
不过注意到我们在除以 \(f(S)^2\) 之后不可能除出来一个 \(0\) 的负次幂,所以对于分子中 \(0\) 的非最低次项他除完分母之后 \(0\) 的幂一定 \(>0\),所以贡献一定为 \(0\),因此在做加减法的时候直接舍弃次幂大的那个即可。

code

#include<bits/stdc++.h>
#define Debug puts("-------------------------")
using namespace std;
const int N=(1<<20)+5,mod=998244353,inv2=(mod+1)/2;inline int read(){int w=1,s=0;char c=getchar();for(;c<'0'||c>'9';w*=(c=='-')?-1:1,c=getchar());for(;c>='0'&&c<='9';s=s*10+c-'0',c=getchar());return w*s;
}
int c,T,n,a[N],p[30],p2[30];
int qp(int a,int b){int ans=1;while(b){if(b&1) ans=1ll*ans*a%mod;b>>=1,a=1ll*a*a%mod;}return ans;
}
struct Val{int x,k;Val() : x(0),k(0) {}Val(int _x,int _k) : x(_x),k(_k) {}
}f[N],g[N],h[N],F[N]; 
Val operator * (const Val &u,const Val &v){return Val(1ll*u.x*v.x%mod,u.k+v.k);}
Val operator + (const Val &u,const Val &v){if(u.k==v.k) return Val((u.x+v.x)%mod,u.k);return u.k<v.k?u:v;
}
Val operator - (const Val &u,const Val &v){if(u.k==v.k) return Val((u.x-v.x+mod)%mod,u.k);return u.k<v.k?u:v;
}
void OR(Val *a,int t){for(int i=1;i<(1<<n);i<<=1){for(int len=i<<1,j=0;j<(1<<n);j+=len){for(int k=0;k<i;k++){if(t==1) a[j+k+i]=a[j+k+i]+a[j+k];else a[j+k+i]=a[j+k+i]-a[j+k];}}}
}	
signed main(){p[0]=p2[0]=1;for(int i=1;i<=25;i++) p[i]=(mod-2*p[i-1]%mod)%mod,p2[i]=1ll*p2[i-1]*inv2%mod;c=read(),T=read();while(T--){n=read();for(int i=0;i<(1<<n);i++){a[i]=read();f[i]=(a[i]+1==mod)?Val(1,1):Val(a[i]+1,0);g[i]=(2*a[i]+1==mod)?Val(1,1):Val((2*a[i]+1)%mod,0);}for(int i=0;i<n;i++){for(int s=0;s<(1<<n);s++){if(!(s>>i&1)) f[s]=f[s]*f[s|(1<<i)],g[s]=g[s]*g[s|(1<<i)];}}for(int s=0;s<(1<<n);s++) F[s]=Val(1ll*f[s].x*p[__builtin_popcount(s)]%mod,f[s].k);OR(F,1);for(int s=0;s<(1<<n);s++) h[s]=F[s]*F[s];OR(h,-1);int ans=0;for(int s=0;s<(1<<n);s++){Val t1=h[s]*g[s],t2=f[s]*f[s];if(t1.k==t2.k) (ans+=1ll*t1.x*qp(t2.x,mod-2)%mod*p2[__builtin_popcount(s)]%mod)%=mod;}printf("%d\n",ans);}return 0;
}
http://www.hskmm.com/?act=detail&tid=24091

相关文章:

  • bi数据报表发送周期,周报和月报获取日期时间
  • 技术Leader的1-3-5沟通法则:向上管理的艺术 - 指南
  • cannot resolve method add in T 及 T 泛型类型生成Excel文件,区别是数据Model不同
  • 测试环境elasticSearch数据泄露排查
  • 深入解析:Spring boot中 限制 Mybatis SQL日志的大字段输出
  • 【AI时代速通QT】第九节:揭秘Qt编译全流程-从.pro材料到可执行程序
  • 考试心得5
  • javascript高级 - Ref
  • Solar9月赛wp - 场
  • 实用指南:深度解析Sora2:技术革命与创意产业的未来图景
  • 自动化安全工具的双刃剑:红队演练揭示安全响应盲区
  • Elastic Search 安装部署最全教程(Docker)
  • 详细介绍:图像分割:PyTorch从零开始实现SegFormer语义分割
  • 深入解析:Playwright同步、异步、并行、串行执行效率比较
  • 2025十一集训——Day2模拟赛
  • 2025十一集训——Day模拟赛
  • Qt纯代码实现智能安防集中管理平台/楼宇对讲管理系统/门禁管理/视频监控
  • 汉文博士词典库源文件已在 github 开放
  • 读人形机器人30未来20年
  • Flutter + Ollama:开启本地AI的全平台新纪元 —— 从零剖析一款现代化AI客户端的技能奥秘
  • 股票资料API接口全解析:从技术原理到多语言实战(含实时行情、MACD、KDJ等技术指标数据与API文档详解)
  • 产业园区招商团队快躺平了 - 智慧园区
  • 洛谷 P3545
  • 题解:AT_wtf22_day2_b The Greatest Two
  • 威胁狩猎实战:终端攻击行为分析与检测
  • 实用指南:基于Hadoop+Spark的人体体能数据分析与可视化系统开源实现
  • 英语_阅读_Water Sliding_待读
  • 实用指南:ArcGIS JSAPI 高级教程 - 高亮效果优化之开启使用多高亮样式
  • const在for用不了
  • about me