「CodePlus 2017 12 月賽」白金元首與獨舞
阿新 • • 發佈:2018-08-18
srand tac -a swap int 生成 pair 之間 意義
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\n",solve()); } return 0; }
「CodePlus 2017 12 月賽」白金元首與獨舞