• bzoj 1494 生成树计数


    坑了好多天的题,终于补上了
    首先发现 (i) 这个点和 (i-k) 之前的点没有边,所以 (i-k) 之前的点肯定联通,只要处理中间 (k) 个点的联通状态就好了。我们用最小表示法,(f[i]) 表示最小的与 (i) 联通的点编号,发现状态最多有52种,然后枚举下一个点与那些点之间连边,得到转移方程,矩阵快速幂优化转移即可

    (反正怎么说估计都听不懂,还是贴代码比较靠谱)

    #include<stdio.h>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<string>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair<long long,long long> pll;
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define rep(i,j,k)  for(register int i=(int)(j);i<=(int)(k);i++)
    #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
    
    ll read(){
    	ll x=0,f=1;char c=getchar();
    	while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    
    const int mod=65521;
    
    ll n,k;
    int tot,f[20],sta[100][20],a[20],cnt[100],num[20],edge[20];
    
    struct Matrix{
    	int mat[60][60];
    	Matrix(int x){
    		memset(mat,0,sizeof(mat));
    		if(x) rep(i,1,tot) mat[i][i]=1;
    	}
    	Matrix operator*(Matrix ano){
    		Matrix ret(0);
    		rep(i,1,tot)
    			rep(j,1,tot)
    				rep(k,1,tot)
    					ret.mat[i][j]=(ret.mat[i][j]+mat[i][k]*1ll*ano.mat[k][j])%mod;
    		return ret;
    	}
    	Matrix operator^(ll k){
    		Matrix ret(1),xx(0);
    		memcpy(xx.mat,mat,sizeof(mat));
    		while(k){
    			if(k&1) ret=ret*xx;
    			xx=xx*xx;k>>=1;
    		}
    		return ret;
    	}
    	void pr(){
    		rep(i,1,tot){
    			rep(j,1,tot){
    				printf("%d ",mat[i][j]);
    			}
    			puts("");
    		}
    		puts("");
    	}
    } trans(0);
    
    int ksm(int x,int p){
    	int ret=1;
    	while(p){
    		if(p&1) ret=ret*x;
    		x=x*x;
    		p>>=1;
    	}
    	return ret;
    }
    //处理当前状态的生成树个数
    //公式 大小为n的完全图生成树个数为n^(n-2)
    void calc(int x){
    	memset(f,0,sizeof(f));cnt[x]=1;
    	rep(i,1,k) f[sta[x][i]]++;
    	for(int i=1;f[i];i++) if(f[i]>2) cnt[x]*=ksm(f[i],f[i]-2);
    }
    //前x个分成了s个联通块的方案
    void dfs1(int x,int s){
    	if(x==k+1){
    		tot++;
    		rep(i,1,k) sta[tot][i]=a[i];
    		calc(tot);return;
    	}
    	for(int i=1;i<=s+1;i++) a[x]=i,dfs1(x+1,max(i,s));
    }
    
    inline bool issame(int x[],int b[]){
    	rep(i,1,k) if(x[i]!=b[i]) return 0;
    	return 1;
    }
    //求此时的状态是什么
    inline void get1(int id){
    	memcpy(a,sta[id],sizeof(a));
    	rep(i,1,k){
    		if(edge[i]){
    			if(!a[k+1]) a[k+1]=a[i];
    			else{
    				int x=a[i];
    				rep(j,1,k) if(a[j]==x) a[j]=a[k+1];
    			}
    		}
    	}
    	rep(i,1,k) a[i]=a[i+1];
    	memset(num,0,sizeof(num));int num1=0;
    	rep(i,1,k){
    		if(!num[a[i]]) num[a[i]]=++num1;
    		a[i]=num[a[i]];
    	}
    	rep(i,1,tot) if(issame(a,sta[i])){
    		trans.mat[id][i]++;
    		return;
    	}
    }
    //求id能够转移到什么状态
    void dfs2(int id,int x){
    	if(x==k+1){
    		get1(id);return;
    	}
    	dfs2(id,x+1);	//不连k+1到x的边
    	if(!f[sta[id][x]]){	//k+1到这个联通块目前没有边,可以连
    		//连k+1到x的边
    		f[sta[id][x]]=1;edge[x]=1;
    		dfs2(id,x+1);
    		f[sta[id][x]]=0;edge[x]=0;
    	}
    }
    
    int main(){
    	k=read(),n=read();
    	dfs1(1,0);
    	//处理转移
    	rep(i,1,tot){
    		memset(f,0,sizeof(f));
    		memset(edge,0,sizeof(edge));
    		bool flag=1;
    		rep(j,2,k) if(sta[i][j]==1){
    			flag=0;break;
    		}
    		if(flag){
    			//没有出现过与1相连的边,所以下一条边必须和1相连
    			f[1]=1;edge[1]=1;dfs2(i,2);
    		}
    		else dfs2(i,1);
    	}
    	trans=trans^(n-k);
    	ll ans=0;
    	rep(i,1,tot) ans=(ans+trans.mat[i][1]*1ll*cnt[i])%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    WCF 、Web API 、 WCF REST 和 Web Service 的区别
    BusyIndicator using MVVM 忙碌状态指示器的的实现
    复制文件夹的方法 .net
    SQL/LINQ/Lamda
    CSLA验证规则总结
    C++中GB2312字符串和UTF-8之间的转换
    如何用VC编写供PB调用的DLL
    【转】lucene4.3.0 配置与调试
    cygwin主要命令
    【转】eclipse中window->preference选项中没有tomcat的解决方法
  • 原文地址:https://www.cnblogs.com/wawawa8/p/9754988.html
Copyright © 2020-2023  润新知