zoukankan      html  css  js  c++  java
  • 某个奇怪的引理 学习总结

    貌似跟OI的关系不是很密切?

    但是既然考到了就来学习一发

    吐槽一下今天的题目:

    第二题要用这个奇怪的引理(其实貌似用容斥原理可以直接推?

    第三题要用格林公式(根本不会

    然后就考得非常的惨烈

    这个引理的名字叫Lindström–Gessel–Viennot

    具体可以去wiki一下QAQ

    貌似是用来解决网格图不相交路径计数的

    题目类型貌似很单一,通常都是上面有点集A,下面有点集B,然后求每个A到对应B的不相交路径总数

    可能还会有一些限制QAQ

    然后我们考虑我们求出f(i,j)表示A的第i个点到B的第j个点的路径方案

    考虑如果设排列P,我们考虑i->P(i)

    则这个排列有多少个逆序对就至少有多少个交点

    这里出现了至少,我们可以考虑容斥原理

    写出容斥原理的式子之后我们会得到一个O(n!)的算法

    之后仔细(不用)观察会发现容斥原理的式子实际上就是求行列式

    然后O(n^3)求行列式即可

    以上是本蒟蒻的理解,具体证明还是看wiki吧

    至于f(i,j)的求解,依据题目选择合适的DP

    codeforces #202 div1  D

    直接O(nm)DP可以求出f(i,j),之后直接上引理就可以了

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef long long LL;
    const int mod=1000000007;
    const int maxn=3010;
    int n,m;
    char c[maxn][maxn];
    int dp[maxn][maxn];
    int f[3][3];
    
    int Get_DP(int qx,int qy,int zx,int zy){
    	memset(dp,0,sizeof(dp));
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(c[i][j]=='#')continue;
    			if(i==qx&&j==qy){dp[i][j]=1;continue;}
    			dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
    		}
    	}return dp[zx][zy];
    }
    int det(int n){
    	int ret=1;
    	for(int i=1;i<=n;++i){
    		for(int j=i+1;j<=n;++j){
    			while(f[j][i]){
    				LL tmp=f[i][i]/f[j][i];
    				for(int k=i;k<=n;++k)f[i][k]=(f[i][k]-tmp*f[j][k]%mod+mod)%mod;
    				for(int k=i;k<=n;++k)swap(f[i][k],f[j][k]);
    				ret=-ret;
    			}
    		}
    		if(f[i][i]==0)return 0;
    		ret=1LL*ret*f[i][i]%mod;
    	}return (ret%mod+mod)%mod;
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			c[i][j]=getchar();
    			while(c[i][j]<'!')c[i][j]=getchar();
    		}
    	}
    	f[1][1]=Get_DP(2,1,n,m-1);
    	f[1][2]=Get_DP(2,1,n-1,m);
    	f[2][1]=Get_DP(1,2,n,m-1);
    	f[2][2]=Get_DP(1,2,n-1,m);
    	printf("%d
    ",det(2));
    	return 0;
    }
    

    然后就是今天的题目QAQ

    貌似不能多说些什么

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef long long LL;
    const int mod=998244353;
    const int maxn=420;
    int n,m,p,q,cnt;
    int jc[300010],inv[300010];
    int a[maxn],b[maxn];
    int f[maxn][maxn];
    int dp[maxn<<1];
    struct Point{
    	int x,y;
    }c[maxn<<1];
    
    bool cmp(const Point &A,const Point &B){
    	if(A.x==B.x)return A.y<B.y;
    	return A.x<B.x;
    }
    int pow_mod(int v,int p){
    	int tmp=1;
    	while(p){
    		if(p&1)tmp=1LL*tmp*v%mod;
    		v=1LL*v*v%mod;p>>=1;
    	}return tmp;
    }
    bool pd(int x,int y,int i){return x<=c[i].x&&y<=c[i].y;}
    int C(int n,int m){return 1LL*jc[n]*inv[m]%mod*inv[n-m]%mod;}
    void Get_f(int now,int qx,int qy){
    	memset(dp,0,sizeof(dp));
    	for(int i=1;i<=cnt;++i){
    		if(pd(qx,qy,i)){
    			dp[i]=C(c[i].x+c[i].y-qx-qy,c[i].x-qx);
    			for(int j=1;j<i;++j){
    				if(pd(c[j].x,c[j].y,i)&&dp[j]){
    					dp[i]=dp[i]-1LL*C(c[i].x+c[i].y-c[j].x-c[j].y,c[i].x-c[j].x)*dp[j]%mod;
    					if(dp[i]<0)dp[i]+=mod;
    				}
    			}
    		}
    	}
    	for(int i=q+1;i<=cnt;++i)f[now][i-q]=dp[i];
    }
    int det(int n){
    	int ret=1;
    	for(int i=1;i<=n;++i){
    		for(int j=i+1;j<=n;++j){
    			while(f[j][i]){
    				LL tmp=f[i][i]/f[j][i];
    				for(int k=i;k<=n;++k)f[i][k]=(f[i][k]-tmp*f[j][k]%mod+mod)%mod;
    				for(int k=i;k<=n;++k)swap(f[i][k],f[j][k]);
    				ret=-ret;
    			}
    		}
    		if(f[i][i]==0)return 0;
    		ret=1LL*ret*f[i][i]%mod;
    	}return (ret%mod+mod)%mod;
    }
    
    int main(){
    	scanf("%d%d%d%d",&n,&m,&p,&q);
    	jc[0]=1;
    	for(int i=1;i<=n+m;++i)jc[i]=1LL*jc[i-1]*i%mod;
    	inv[n+m]=pow_mod(jc[n+m],mod-2);
    	for(int i=n+m-1;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
    	for(int i=1;i<=p;++i)scanf("%d",&a[i]);
    	for(int i=1;i<=p;++i)scanf("%d",&b[i]);
    	sort(a+1,a+p+1);sort(b+1,b+p+1);
    	for(int i=1;i<=q;++i)scanf("%d%d",&c[i].x,&c[i].y);
    	sort(c+1,c+q+1,cmp);cnt=q;
    	for(int i=1;i<=p;++i)cnt++,c[cnt].x=n,c[cnt].y=b[i];
    	for(int i=1;i<=p;++i)Get_f(i,0,a[i]);
    	printf("%d
    ",det(p));
    	return 0;
    }
    

      

  • 相关阅读:
    Redis源码分析(二十一)--- anet网络通信的封装
    leetcode 总结part1
    leetcode String to Integer (atoi)
    leetcode 165. Compare Version Numbers
    leetcode 189. Rotate Array
    leetcode 168. Excel Sheet Column Title
    leetcode 155. Min Stack
    leetcode 228. Summary Ranges
    leetcode 204. Count Primes
    leetcode 6. ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/joyouth/p/5607781.html
Copyright © 2011-2022 走看看