uoj #37. 【清华集训2014】主旋律

考虑原先求的是 SCC 为 1 的方案数,这很困难!因为并没有能够转移到子问题的路径。

不妨考虑容斥,即 SCC 为 1 的方案数=所有方案数-SCC 不为 1 的方案数。

不妨先集合划分出 SCC,然后就变成了,内部的 SCC 子问题(此时因为钦定的 SCC 个数 >1,因此规模一定变小)以及外层的 DAG 计数。

不妨先考虑内层的 DAG 计数。

此时与原问题、原图没有一点关系!我们仅仅考虑一般有向图的删边后成为 DAG 这个子问题!!!

即当前图有若干个入度为 0 的点。考虑我们拓扑的过程,把这入度为 0 的点都搞一次之后删去其出边,之后一定又出现若干入度为 0 的点,否则因为其是个 DAG,则拓扑结束。也就是说,当我们钦定入度为 0 的点之后,我们将 DAG 计数转为了子规模的 DAG 计数。

即设 t(S) 为点集 S 的点导出子图的删边后成为 DAG 的方案数,f(T,S)S 中恰好入度为 0 的点集为 T 的 DAG 方案数。但恰好很难求,考虑钦定。即 g(T,S) 为钦定 S 中入度为 0 的点集为 T 的 DAG 方案数。

则有

g(T,S)=TRf(R,S)

子集反演

f(T,S)TR(1)|R||T|g(R,S)

t(S)=TS,Tϕf(T,S)

TS,Tϕf(T,S)=TS,TϕTRS,Rϕ(1)|R||T|g(R,S)=...=RS,Rϕ(1)|R|+1g(R,S)

注意到,此时的 DAG 计数仅仅与你钦定的入度为 0 的点集有关!

考虑回到原问题,即考虑钦定点集 T 作为入度为 0 的 SCC 的点集,但其内部的 SCC 还要集合划分!但我们只关心什么?因为是钦定!!!对于容斥系数而言,我们只关心其划分的 SCC 的个数的奇偶以及其方案数。

考虑记 f1(S)S 的点集划分出奇数个 SCC 的方案数,f0(S) 为偶数个。

dp(S) 为删边使得其为 DAG 的方案数。

那么我们有 dp(S)=2c(S,S)2

考虑钦定点集 T 作为入度为 0 的 SCC 点集,注意是钦定。那么就变成了 T 自己内部的子问题。又因为我们要求当前 SCC 个数 >1,所以并不会回到当前规模的问题!!!

那么要如何求 dp(S),为 S 划分出 >1 个 SCC 的方案数/yiw

考虑缩点后的图,既然只关心 T,那么钦定完之后,其他咋办!考虑 g(T,S) 在原问题的定义是钦定 T 中的点缩完点后在入度为 0 的 SCC 内!所以可以存在不属于 T 的点存在于入度为 0 的 SCC 内。因此钦定完,就直接瞎连了。

那么我们有 dp(S)=TS,Tϕ(f1(T)f0(T))2c(T,ST)+c(ST,ST),不难发现,我们实际上就是在考虑其缩点后的情况。也就是说,本质就是在用 g 去贡献啦。只是对应的图一张是原图,一张是缩点后的图。并且,这个时候,我们当前数到的 SCC 数量一定 >1,这是因为,可能 =1 的情况当且仅当 T=S,而我们钦定的 f1(S),f0(S) 此时均没有包含只有一个 SCC 的情况!我们并不会回到当前规模的问题,所以没事。

然后 f1,f0 的转移是平凡的,考虑钦定其中某一个点所在的 SCC 的点集即可转移。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int mod=(int)(1e9+7); pair<int,int>e[1000]; int dp[(1<<15)],f0[(1<<15)],f1[(1<<15)],n,m,ou[(1<<15)],pw[1000]; inline int cal(int S,int T) { int res=0; while(S) { int x=(S&(-S)); res+=__builtin_popcount(ou[x]&T); S-=x; } return res; } signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; --x; --y; e[i]=make_pair(x,y); ou[1<<x]|=(1<<y); } pw[0]=1; for(int i=1;i<=m;i++) pw[i]=pw[i-1]*2%mod; for(int S=1;S<(1<<n);S++) { int p=__builtin_ffs(S); // for(int i=0;i<n;i++) { // if((S>>i)&1) { // p=i; break ; // } // } int SS=(S^p); for(int T=SS;;T=(T-1)&SS) { int TT=(T|p); f1[S]=(f1[S]+dp[TT]*f0[S^TT]%mod)%mod; f0[S]=(f0[S]+dp[TT]*f1[S^TT]%mod)%mod; // del[S]=(del[S]-dp[TT]*del[S^TT]%mod)%mod; if(!T) break ; } dp[S]=pw[cal(S,S)]; for(int T=S;T;T=(T-1)&S) { dp[S]=(dp[S]-(f1[T]-f0[T]+mod)%mod*pw[cal(T,(S^T))]%mod*pw[cal((S^T),(S^T))]%mod)%mod; dp[S]=(dp[S]%mod+mod)%mod; }f1[S]=(f1[S]+dp[S])%mod; // cout<<dp[S]<<" "<<del[S]<<'\n'; } cout<<(dp[(1<<n)-1]%mod+mod)%mod; return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/17238807.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示