LGV引理小记
由于是看 oi-wiki 学的,内容基本是搬过来的。
小前提: LGV 引理仅适用于有向无环图。
定义
表示 这条路径上所有边的边权之积。(路径计数时,可以将边权都设为 )(事实上,边权可以为生成函数)
表示从 到 的每一条路径 的 之和,即 。
起点集合 ,是有向无环图点集的一个子集,大小为 。
终点集合 ,也是有向无环图点集的一个子集,大小也为 。
一组 的不相交路径 : 是一条从 到 的路径( 是一个排列),对于任何 , 和 没有公共顶点。
表示排列 的逆序对个数。
引理
其中 表示满足上文要求的 的每一组不相交路径 。
证明
由行列式定义可得
观察到 ,实际上是所有从 到 排列为 的路径组 的 之和。
此处 为任意路径组。
设 为不相交路径组, 为相交路径组,
设 中存在一个相交路径组 ,,则必然存在和它相对的一个相交路径组 ,, 的其他路径与 相同。可得 。
因此我们有 。
则 。
证毕。
例题
CF348D Turtles
比较直接的 LGV 引理的应用。考虑所有合法路径,发现从 出发一定要经过 ,而到达终点一定要经过 ,则 可立即选定。应用 LGV 引理可得答案为:
其中 为图上 的路径数,带有障碍格点的路径计数问题可以直接做一个 的 dp,则 易求。最终复杂度 。
点击查看代码
#include<bits/stdc++.h> #define int long long using namespace std; const int MOD=1e9+7; const int MAXN=3e3+5; int n,m; int dp[MAXN][MAXN]; char ma[MAXN][MAXN]; inline int solve(int x1,int y1,int x2,int y2) { memset(dp,0,sizeof(dp)); dp[x1][y1]=(ma[x1][y1]=='.'); for(int i=1;i<=x2;i++) for(int j=1;j<=y2;j++) { if(ma[i][j]=='#') continue; dp[i][j]=(dp[i][j]+dp[i-1][j])%MOD; dp[i][j]=(dp[i][j]+dp[i][j-1])%MOD; } return dp[x2][y2]%MOD; } signed main() { ios_base::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>ma[i][j]; int res1=solve(1,2,n-1,m); int res2=solve(1,2,n,m-1); int res3=solve(2,1,n-1,m); int res4=solve(2,1,n,m-1); int ans=((res1*res4)%MOD-(res2*res3)%MOD+MOD)%MOD; printf("%lld\n",ans); return 0; }
本文作者:Code_AC
本文链接:https://www.cnblogs.com/code-ac/p/17721904.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步