zoukankan      html  css  js  c++  java
  • 幻想乡三连A:五颜六色的幻想乡

     

    非常直接地构造

    由于答案与生成树计数有关,所以一定要使用矩阵树定理,但这样就不能限制每种颜色的便使用的数量

    我们构造$N^2$个关于$Ans_{x,y}$的方程,枚举将红色的边拆成$x$条,将蓝色的边拆成$y$条,跑一遍矩阵树定理,就得到$$G_{x,y}=sumlimits_{i=0}^{n-1} sumlimits_{j=0}^{n-i-1} Ans_{i,j}cdot x^icdot y^j$$然后会发现$Ans_{i,j}$可以看做这个二维多项式的系数,直接用拉格朗日插值构造得解。

     

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define mod 1000000007
    #define M 60
    using namespace std;
    int read(){
    	int nm=0,fh=1; char cw=getchar();
    	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    int n,m,u[M*M],v[M*M],kd[M*M],mat[M][M],T[M][M],ans[M][M];
    int X[M],Y[M],tmp,V[M][M];
    int add(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
    int mus(int x,int y){return (x-y)<0?x-y+mod:x-y;}
    int mul(int x,int y){return (LL)x*(LL)y%mod;}
    void upd(int &x,int y){x=add(x,y);}
    int qpow(int x,int sq){
    	int res=1;
    	while(sq){if(sq&1) res=mul(res,x);x=mul(x,x),sq>>=1;}
    	return res;
    }
    int init(int x,int y){
    	const int w[4]={0,x,y,1};
    	int dt,inv,now=1,ot;
    	memset(mat,0,sizeof(mat));
    	for(int i=1;i<=m;i++){
    	    upd(mat[u[i]][v[i]],mod-w[kd[i]]),upd(mat[u[i]][u[i]],w[kd[i]]);
    		upd(mat[v[i]][u[i]],mod-w[kd[i]]),upd(mat[v[i]][v[i]],w[kd[i]]);
    	}
    	for(int i=1;i<n;i++){
    		for(ot=i;ot<n&&mat[ot][i]==0;ot++);
    		if(ot>=n) return 0;
    		if(ot!=i){now=mod-now;for(int j=i;j<n;j++) swap(mat[i][j],mat[ot][j]);}
    		now=mul(now,mat[i][i]),inv=qpow(mat[i][i],mod-2);
    		for(int j=i+1;j<n;j++){
    			if(!mat[j][i]) continue; dt=mul(mat[j][i],inv);
    			for(int k=i;k<n;k++) mat[j][k]=mus(mat[j][k],mul(dt,mat[i][k]));
    		}
    	}
    	return now;
    }
    void solve(int x,int y){
    	memset(X,0,sizeof(X)),X[0]=1;
    	memset(Y,0,sizeof(Y)),Y[0]=1;
    	tmp=T[x][y];
    	for(int i=1;i<=n;i++){
    		if(i!=x){
    		    for(int j=i;j;j--) X[j]=mus(X[j-1],mul(X[j],i));
    		    X[0]=mul(X[0],mod-i),tmp=mul(tmp,V[x][i]);
    		}
    		if(i!=y){
    		    for(int j=i;j;j--) Y[j]=mus(Y[j-1],mul(Y[j],i));
    		    Y[0]=mul(Y[0],mod-i),tmp=mul(tmp,V[y][i]);
    		}
    	}
    	for(int i=0;i<n;i++) for(int j=0;j+i<n;j++) upd(ans[i][j],mul(tmp,mul(X[i],Y[j])));
    }
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=m;i++) u[i]=read(),v[i]=read(),kd[i]=read();
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) T[i][j]=init(i,j);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) V[i][j]=qpow(mus(i,j),mod-2);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) solve(i,j);
    	for(int i=0;i<n;i++) for(int j=0;i+j<n;j++) printf("%d
    ",ans[i][j]);
    	return 0;
    }
  • 相关阅读:
    递归 深拷贝
    js 基础复习(0)
    js数组冒泡排序,快速排序的原理以及实现
    .sass 和 .scss 区别
    ionic2-从搭建环境说起
    Unity3d截图保存到Android相册的实现
    总是要总结一年的工作(写给自己和想要从技术创业开公司的朋友们)
    初入职场(插曲-如何更称职的工作)
    初入职场(插曲-你的成长代价)
    初入职场(面试)
  • 原文地址:https://www.cnblogs.com/OYJason/p/9662227.html
Copyright © 2011-2022 走看看