• 某个奇怪的引理 学习总结


    貌似跟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;
    }
    

      

  • 相关阅读:
    用Fusion Log诊断同一版本冲突问题解决
    SQLSERVER 切换数据库为单用户和多用户模式
    redis常用命令
    linq函数All,Any,Aggregate说明
    rabbitmq部署安装
    Centos7防火墙常用命令
    SQL SERVER添加表注释、字段注释
    Windows定时任务管理以及服务管理
    SQLServer 2008数据库查看死锁、堵塞的SQL语句
    SQLServer查询死锁
  • 原文地址:https://www.cnblogs.com/joyouth/p/5607781.html
Copyright © 2020-2023  润新知