zoukankan      html  css  js  c++  java
  • 「CodePlus 2017 12 月赛」白金元首与独舞

    description

    题面

    data range

    [1 leq T leq 10, 1 leq n, m leq 200 , 0 leq k leq min(nm, 300) ]

    solution

    矩阵树定理

    求无向图的生成树个数

    度数矩阵-邻接矩阵

    去掉一行一列求行列式

    为了保证精度可以辗转相除

    这里是模意义下的

    const int mod=998244353;
    int a[305][305];
    il int gauss(int n){
    	RG int ans=1;
    	for(RG int i=2;i<=n;i++){
    		for(RG int j=i+1;j<=n;j++)
    			while(a[j][i]){
    				RG int t=a[i][i]/a[j][i];
    				for(RG int k=i;k<=n;k++)dec(a[i][k],1ll*t*a[j][k]%mod);
    				swap(a[i],a[j]);if(ans)ans=mod-ans;
    			}
    		ans=1ll*ans*a[i][i]%mod;
    	}
    	if(ans<0)ans+=mod;return ans;
    }
    

    有向图的外向(父亲指向儿子)生成树个数

    对于每条边((u,v))(a[v][v]++,a[u][v]--)(把度数看成入度)

    然后直接求行列式即可

    这题的解法

    首先判掉无解

    然后我们发现题目中每个空格方向的选择决定了空格之间的到达关系

    于是这道题目变成了一个求内向生成树个数的题

    套上矩阵树定理即可

    code

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<ctime>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define FILE "a"
    #define mp make_pair
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e9+7;
    const int N=2000010;
    const dd pi=acos(-1);
    const int inf=2147483645;
    const ll INF=1e18+1;
    const ll P=100000;
    il ll read(){
    	RG ll data=0,w=1;RG char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    	return data*w;
    }
    
    il void file(){
    	srand(time(NULL)+rand());
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    }
    
    int n,m,p[305][305],kx[305],ky[305];
    int id[305][305],tag[305][305],t[100010],cnt,tot;
    int a[305][305];
    int dx[]={0,0,-1,1},dy[]={-1,1,0,0};
    il void init(){
    	memset(id,0,sizeof(id));
    	memset(tag,0,sizeof(tag));
    	memset(t,0,sizeof(t));
    	memset(a,0,sizeof(a));
    	n=read();m=read();tot=1;cnt=0;
    	for(RG int i=1,c;i<=n;i++)
    		for(RG int j=1;j<=m;j++){
    			a[i][j]=tag[i][j]=id[i][j]=c=0;
    			while(c!='L'&&c!='R'&&c!='U'&&c!='D'&&c!='.')c=getchar();
    			if(c=='L')p[i][j]=0;if(c=='R')p[i][j]=1;
    			if(c=='U')p[i][j]=2;if(c=='D')p[i][j]=3;
    			if(c=='.'){p[i][j]=4;id[i][j]=++tot;kx[tot]=i;ky[tot]=j;}
    		}
    }
    
    il bool work(){
    	for(RG int i=1;i<=n;i++)
    		for(RG int j=1;j<=m;j++)
    			if(!id[i][j]&&!tag[i][j]){
    				RG int x=i,y=j,w=p[i][j];cnt++;
    				RG int xx=x+dx[w],yy=y+dy[w];
    				while(!id[x][y]&&!tag[x][y]&&x>0&&y>0&&x<=n&&y<=m){
    					tag[x][y]=cnt;x=xx;y=yy;w=p[x][y];xx=x+dx[w];yy=y+dy[w];
    				}
    				if(id[x][y])t[cnt]=id[x][y];
    				else if(x<1||y<1||x>n||y>m)t[cnt]=1;
    				else if(tag[x][y]==cnt)return 0;
    				else if(tag[x][y])t[cnt]=t[tag[x][y]];
    			}
    	return 1;
    }
    
    il void upd(int &a,int b){a+=b;if(a>=mod)a-=mod;}
    il void dec(int &a,int b){if(b)upd(a,mod-b);}
    il int gauss(int n){
    	RG int ans=1;
    	for(RG int i=2;i<=n;i++){
    		for(RG int j=i+1;j<=n;j++)
    			while(a[j][i]){
    				RG int t=a[i][i]/a[j][i];
    				for(RG int k=i;k<=n;k++)dec(a[i][k],1ll*t*a[j][k]%mod);
    				swap(a[i],a[j]);if(ans)ans=mod-ans;
    			}
    		ans=1ll*ans*a[i][i]%mod;
    	}
    	if(ans<0)ans+=mod;return ans;
    }
    il int solve(){
    	for(RG int i=2;i<=tot;i++)
    		for(RG int w=0;w<=3;w++){
    			RG int xx=kx[i]+dx[w],yy=ky[i]+dy[w];
    			RG int u=t[tag[xx][yy]],v=i;
    			if(id[xx][yy])u=id[xx][yy];
    			if(xx<1||yy<1||xx>n||yy>m)u=1;
    			if(u==v||!u)continue;
    			a[v][v]++;if(!a[u][v])a[u][v]=mod;a[u][v]--;
    		}
    	return gauss(tot);
    }
    
    int main()
    {
    	RG int T=read();
    	while(T--){
    		init();
    		if(!work()){puts("0");continue;}
    		else printf("%d
    ",solve());
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    mysql密码忘记如何恢复(windows/liunx版本:mysql8.0.27)
    Visual Studio Code如何校验yaml格式文件
    python测试小工具
    Lunx vimgo 开发环境搭建
    小白学正则表达式之 regexp
    kubernetes scc 故障排查小记
    Go image registry
    OpenShift image registry 概述
    Go 疑难杂症汇总
    小白学标准库之 http
  • 原文地址:https://www.cnblogs.com/cjfdf/p/9497567.html
Copyright © 2011-2022 走看看