对于一张无边权的DAG图,给定n个起点和对应的n个终点,这n条不相交路径的方案数为
det() (该矩阵的行列式)
其中e(a,b)为图上a到b的方案数
codeforces 348D
[给定一张n*m带障碍的图,求从左上角到右下角不相交两条路径的方案]
[a1=(1,2) a2=(2,1) b1=(n-1,m) b2=(n,m-1) 应用该定理即可]
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 3005;
const ll mod = 1e9+7;
ll dp1[maxn][maxn];
ll dp2[maxn][maxn];
int mp[maxn][maxn];
int n,m;
int main()
{
char s[maxn];
while(~scanf("%d%d",&n,&m))
{
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++)
{
scanf("%s",s);
for(int j=0;j<m;j++)
{
if(s[j]=='.')mp[i][j+1]=1;
}
}
dp1[1][1]=1;
dp2[1][1]=1;
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
if(mp[i][j])
dp1[i][j]=(dp1[i-1][j]+dp1[i][j-1])%mod;
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j])
dp2[i][j]=(dp2[i-1][j]+dp2[i][j-1])%mod;
printf("%I64d\n",((dp1[n-1][m]*dp2[n][m-1])%mod-(dp1[n][m-1]*dp2[n-1][m])%mod+mod)%mod);
}
}
HDU 5852
[给一张n*n的图,第一行m个点对应第n行的m个点,求路径不相交的方案数]
[计算对应的行列式,注意高斯消元不要T]
[据说Q神想到是行列式之后在机房大喊一声,结果其他队伍都会做了,自己T了:D]
(lindström–gessel–viennot lemma+行列式)
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 100010;
const int maxk = 105;
ll a[maxk],b[maxk];
ll fac[maxn*2];
ll matrix[maxk][maxk];
ll quick_pow(ll a,ll b)
{
ll ans = 1;
while(b)
{
if(b&1)ans = (ans * a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
ll cal(ll n,ll m)
{
ll b = fac[m-1];
ll a = fac[n+m-2];
ll c = fac[n-1];
b = quick_pow(b,mod-2);
c = quick_pow(c,mod-2);
return ((a*b)%mod*c)%mod;
}
void init()
{
fac[0]=fac[1]=1;
for(int i=2;i<maxn*2;i++)
fac[i]=(1ll*i*fac[i-1])%mod;
}
int main()
{
init();
int t;
int k;
ll n;
scanf("%d",&t);
while(t--)
{
bool flag=true;
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=k;i++)
{
scanf("%lld",&b[i]);
if(b[i]<a[i])flag=false;
}
if(!flag)
{
printf("0\n");
continue;
}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(b[j]<a[i])matrix[i][j]=0;
else matrix[i][j]=cal(n,b[j]-a[i]+1);
}
}
bool dance = 0;
ll ans =1;
for(int i=1;i<=k;i++)
{
for(int j=i+1;j<=k;j++)
{
int x=i;
int y=j;
while(matrix[y][i])
{
ll t=matrix[x][i]/matrix[y][i];
for(int p=1;p<=k;p++)
matrix[x][p]=(matrix[x][p]-t*matrix[y][p])%mod;
swap(x,y);
}
if(x!=i)
{
dance^=1;
for(int p=1;p<=k;p++)swap(matrix[i][p],matrix[x][p]);
}
}
ans*=matrix[i][i];
ans=ans%mod;
}
if(dance) ans=ans*(-1);
ans=ans%mod;
ans+=mod;
ans=ans%mod;
printf("%lld\n",ans);
}
}
2018牛客acm暑假多校训练1-A
链接:https://www.nowcoder.com/acm/contest/139/A
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
Count the number of n x m matrices A satisfying the following condition modulo (109+7).
* Ai, j ∈ {0, 1, 2} for all 1 ≤ i ≤ n, 1 ≤ j ≤ m.
* Ai, j ≤ Ai + 1, j for all 1 ≤ i < n, 1 ≤ j ≤ m.
* Ai, j ≤ Ai, j + 1 for all 1 ≤ i ≤ n, 1 ≤ j < m.
输入描述:
The input consists of several test cases and is terminated by end-of-file. Each test case contains two integers n and m.
输出描述:
For each test case, print an integer which denotes the result.
示例1
输入
1 2 2 2 1000 1000
输出
6 20 540949876
备注:
* 1 ≤ n, m ≤ 103
* The number of test cases does not exceed 105.
思路:将2对应的边缘线向右下角移一格,再套用lindström–gessel–viennot lemma求两条不相交路径的方案数。
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn =1005;
ll dp[maxn][maxn];
void init()
{
for(int i=1;i<maxn;i++)
{
dp[i][0]=dp[0][i]=1;
}
for(int i=1;i<maxn;i++)
{
for(int j=1;j<maxn;j++)
{
dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
}
}
}
int main()
{
init();
int n,m;
while(~scanf("%d%d",&n,&m))
{
printf("%lld\n",((dp[n][m]*dp[n][m])%mod-(dp[n-1][m+1]*dp[n+1][m-1])%mod+mod)%mod);
}
}
附录: 该定理wiki