UOJ37 【清华集训2014】主旋律(SCC/DAG 状态压缩)
题意
求一个有向图
分析
SCC 状压有一个非常经典的“耳分解”:以 SCC 内两个点(可以相同)为起点、终点,找一条除两端外不在 SCC 内的链,然后加进去。但是这里要求方案数,耳分解失效,考虑别的方法。
我们知道,DAG 计数的经典方法是枚举点集的一个非空子集
回到原问题,设
最后别忘了把
const int maxn=16,maxm=1<<15,maxk=14348907,mod=1e9+7;
int n,m;
bool vis[maxn][maxn];
int e[maxn][maxm];
int edge[maxm];
int pw[maxn*maxn];
int f[maxm],g[maxm],h[maxk];
int to[maxm];
inline bool in(int S,int x){return (S>>(x-1))&1;}
inline void adder(int &x,int y){x+=y,x=x>=mod?x-mod:x;}
inline void suber(int &x,int y){x-=y,x=x<0?x+mod:x;}
inline void solve_the_problem(){
n=rd(),m=rd();
rep(i,1,m){
int x=rd(),y=rd();
vis[x][y]=1;
}
pw[0]=1;rep(i,1,m)pw[i]=pw[i-1]*2%mod;
const int U=(1<<n)-1;
rep(S,0,U)rep(i,1,n)if(in(S,i))rep(j,1,n)if(in(S,j))edge[S]+=vis[i][j];
rep(i,1,n)rep(S,0,U)rep(j,1,n)if(in(S,j))e[i][S]+=vis[i][j];
rep(S,0,U)rep(i,1,n)to[S]=to[S]*3+in(S,i);
rep(S,1,U){
int p=__builtin_ctz(S),S0=S^(1<<p),S1=U^S;
for(int T=S1;T;T=(T-1)&S1){
h[to[S|T]+to[S]]=h[to[S0|T]+to[S0]]+e[p+1][T];
}
}
rep(S,0,U)f[S]=pw[edge[S]];
rep(S,1,U){
int p=__builtin_ctz(S);
for(int T=(S-1)&S;T;T=(T-1)&S)if((T>>p)&1){
suber(g[S],g[S^T]*f[T]%mod);
}
for(int T=S;T;T=(T-1)&S){
suber(f[S],pw[edge[S^T]+h[to[S]+to[T]]]*g[T]%mod);
}
adder(g[S],f[S]);
}
write(f[U]);
}
复杂度
分类:
动态规划 / 状压 DP
, 动态规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现