CF1326F2 Wise Men (Hard Version)

直接算不好算,考虑先算出超集和的答案,最后高维后缀差分求出原本的答案。

发现超集和的意义下的答案满足:将 01 串的连边关系构成图后,会得到若干条链,若两个 01 串得到的链长的可重集相同,则这两个 01 串的答案相等。因为答案是由全排列贡献的,所以有这个性质。

考虑直接枚举链长的可重集,也就是直接枚举 n 的整数拆分,18 的整数拆分只有 P(18)=385,可以接受。可以通过 DP 求出 gi,S 表示长度为 i 的链,链中的点为 S 的方案数。dfs 过程中用枚举到对应的链长后进行子集卷积即可,因为最后只用取全集的答案,所以这里可以用集合并卷积来代替子集卷积。

总复杂度为 O((n2+P(n))2n)

#include<bits/stdc++.h> #define maxn 20 #define maxm 262154 using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,all; int cnt[maxm]; ll f[maxm],g[maxn][maxm],h[maxn][maxm],v[maxn][maxm]; char w[maxn][maxn]; vector<int> ve; map<vector<int>,ll> mp; void dfs(int x,int pre,int sum) { if(sum==n) { ll val=0; for(int i=0;i<all;++i) val+=v[x][i]*(cnt[i^(all-1)]&1?-1:1); mp[ve]=val; return; } for(int i=pre;i+sum<=n;++i) { for(int j=0;j<all;++j) v[x+1][j]=v[x][j]*g[i][j]; ve.push_back(i),dfs(x+1,i,i+sum),ve.pop_back(); } } int main() { read(n),all=1<<n; for(int i=1;i<all;++i) cnt[i]=cnt[i>>1]+(i&1); for(int i=0;i<n;++i) scanf("%s",w[i]),h[i][1<<i]=1; for(int i=0;i<all;++i) for(int j=0;j<n;++j) for(int k=0;k<n;++k) if(!((i>>k)&1)&&w[j][k]=='1') h[k][i|(1<<k)]+=h[j][i]; for(int i=0;i<all;++i) for(int j=0;j<n;++j) g[cnt[i]][i]+=h[j][i]; for(int x=1;x<=n;++x) for(int len=1;len<all;len<<=1) for(int i=0;i<all;i+=len<<1) for(int j=i;j<i+len;++j) g[x][j+len]+=g[x][j]; for(int i=0;i<all;++i) v[0][i]=1; dfs(0,1,0),all>>=1; for(int s=0;s<all;++s) { ve.clear(); int pos; for(int i=0;i<n;i=pos+1) { pos=i; while(pos<n-1&&(s>>pos)&1) pos++; ve.push_back(pos-i+1); } sort(ve.begin(),ve.end()),f[s]=mp[ve]; } for(int len=1;len<all;len<<=1) for(int i=0;i<all;i+=len<<1) for(int j=i;j<i+len;++j) f[j]-=f[j+len]; for(int i=0;i<all;++i) printf("%lld ",f[i]); return 0; }

__EOF__

本文作者lhm_
本文链接https://www.cnblogs.com/lhm-/p/14586023.html
关于博主:sjzez 的一名 OI 学生
版权声明:转载标明出处
声援博主:希望得到宝贵的建议
posted @   lhm_liu  阅读(79)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示