• 【BZOJ5133】[CodePlus2017年12月]白金元首与独舞 矩阵树定理


    【BZOJ5133】[CodePlus2017年12月]白金元首与独舞

    题面www.lydsy.com/JudgeOnline/upload/201712/div1.pdf

    题解:由于k很小,考虑用矩阵树定理。

    我们先预处理出:从每个已决策点,一直走下去会走到哪个未决策点(我们将最外面看作一个大的未决策点)。可以用拓扑排序搞定,若有环则无解。

    然后我们枚举每个未决策点的四个方向,看一下一直走下去会走到哪个点,在新图中从这个点到终点连一条边。得到新图的出度矩阵和邻接矩阵,求出|出度矩阵-邻接矩阵|即可。

    注:内向树:出度矩阵,外向树:入度矩阵。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #define p(A,B) (((A)-1)*m+(B))
    using namespace std;
    typedef long long ll;
    const ll P=1000000007;
    
    int T,n,m,tot,cnt;
    ll ans;
    int x[310],y[310],from[40010],to[40010],next[40010],head[40010];
    ll v[310][310];
    char str[210][210];
    queue<int> q;
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void work()
    {
    	scanf("%d%d",&n,&m);
    	int i,j,k,a,b,u;
    	memset(from,-1,sizeof(from)),memset(head,-1,sizeof(head)),cnt=tot=0;
    	q.push(0),from[0]=0;
    	for(i=1;i<=n;i++)
    	{
    		scanf("%s",str[i]+1);
    		for(j=1;j<=m;j++)
    		{
    			if(str[i][j]=='.')	x[++tot]=i,y[tot]=j,q.push(p(i,j)),from[p(i,j)]=tot;
    			else
    			{
    				a=i,b=j;
    				if(str[i][j]=='L')	b--;
    				if(str[i][j]=='R')	b++;
    				if(str[i][j]=='U')	a--;
    				if(str[i][j]=='D')	a++;
    				if(!a||!b||a>n||b>m)	add(0,p(i,j));
    				else	add(p(a,b),p(i,j));
    			}
    		}
    	}
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])	from[to[i]]=from[u],q.push(to[i]);
    	}
    	for(i=1;i<=n*m;i++)	if(from[i]==-1)
    	{
    		puts("0");
    		return ;
    	}
    	memset(v,0,sizeof(v));
    	for(i=1;i<=tot;i++)
    	{
    		a=x[i],b=y[i];
    		if(a<n)	v[i][from[p(a+1,b)]]--;
    		if(a>1)	v[i][from[p(a-1,b)]]--;
    		if(b<m)	v[i][from[p(a,b+1)]]--;
    		if(b>1)	v[i][from[p(a,b-1)]]--;
    		v[i][i]+=4;
    	}
    	for(i=1;i<=tot;i++)	for(j=1;j<=tot;j++)	if(v[i][j]<0)	v[i][j]+=P;
    	for(ans=1,i=1;i<=tot;i++)
    	{
    		for(j=i;j<=tot;j++)	if(v[j][i])	break;
    		if(j!=i)	for(ans=P-ans,k=i;k<=tot;k++)	swap(v[i][k],v[j][k]);
    		for(j=i+1;j<=tot;j++)
    		{
    			ll A=v[i][i],B=v[j][i],tmp,temp;
    			while(B)
    			{
    				tmp=A/B,temp=A,A=B,B=temp%B;
    				for(ans=P-ans,k=i;k<=tot;k++)	v[i][k]=(v[i][k]-tmp*v[j][k]%P+P)%P,swap(v[i][k],v[j][k]);
    			}
    		}
    		ans=ans*v[i][i]%P;
    	}
    	printf("%lld
    ",ans);
    }
    int main()
    {
    	//freopen("C.in","r",stdin);
    	scanf("%d",&T);
    	while(T--)	work();
    	return 0;
    }
  • 相关阅读:
    综合练习-词频统计
    组合数据类型综合练习
    Python综合练习
    PostOrder_Traversal 二叉树的非递归后序遍历
    PAT甲级-1152-Google Recruitment(20 分)
    PAT甲级-1007-Maximum Subsequence Sum (25 分)
    macOS MOjave运行pygame不显示图像-解决方案
    PAT甲级-1004-Counting Leaves(30 分)
    Python进阶-Numpy科学计算库(简单入门)
    回文日期
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8125067.html
Copyright © 2020-2023  润新知