HDU 2820 Permutaion

题目拼错系列

我™要是再写这种题我就是狗!!!!!

md调了一天真是智障

首先问题分析一下转化为求哈密尔顿路的个数

基于连通性的状态压缩DP,基于连通性……

但是不能用括号序列表示,所以要用最小表示法

所以大概就是和NOI07的生成树计数差不多吧(我那题代码也写得很挫)

然后大概就是每个点4位,前两位表示所在连通块的标号,后两位表示度数

然后瞎JB搞一下就好了

md连通块合并完了没标号调了一天真是醉了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int p=(1e9)+7;
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
#define mmt(a,v) memset(a,v,sizeof(a))
int n,k;
int get(int s,int i){return ((s>>i)&3)<<i;}
int pa(int s,int i){return (s>>((i-1)<<2))&3;}
int deg(int s,int i){return ((s>>((i-1)<<2))>>2)&3;}
int pro(int i,int p,int d){return (p<<((i-1)<<2))|((d<<((i-1)<<2))<<2);}
int adddeg(int s,int i){return s+((1<<(i<<2))>>2);}
int modifypa(int s,int i,int p){return (s^get(s,(i-1)<<2))|(p<<((i-1)<<2));}
int f[2][70000];
struct Edge{int to,next;}e[100000];
int head[70000],cnt;
void ins(int u,int v){e[++cnt]=(Edge){v,head[u]};head[u]=cnt;}
int state[70000],tot;
int size(int u){
	int ans=0;
	rep(i,1,k)ans=max(ans,pa(u,i));
	return ans;
}
int size(int u,int i){
	int ans=0;
	rep(j,1,k)ans+=pa(u,j)==i;
	return ans;
}
void print(int s){
	rep(i,1,k)printf("%d %d\n",pa(s,i),deg(s,i));
}
void debug(int s){
	puts("!");print(s);puts("~");
}
int dfs(int i,int sc,int s){
	if(i>k)state[++tot]=s;
	else{
		rep(j,0,sc)rep(d,0,2)
		dfs(i+1,sc,s|pro(i,j,d));
		sc++;
		rep(d,0,2)
		dfs(i+1,sc,s|pro(i,sc,d));
	}
}
int merge(int s,int a,int b){
	if(a>b)swap(a,b);
	rep(i,1,k)if(pa(s,i)==b)s=modifypa(s,i,a);
	return s;
}
int remark(int s){
	static bool use[5];mmt(use,0);
	static int ans;ans=s;
	static int sc;sc=0;
	rep(i,1,k){
		if(use[i])continue;
		rep(j,i,k)
		if(pa(s,i)==pa(s,j)){
			use[j]=true;
			ans=modifypa(ans,j,sc);
		}
		sc++;
	}
	return ans;
}
void debug(int u,int v){
	puts("~");print(u);print(v);puts("~");
}
void find(int u){
	static int lim,v,w,t;
	lim=size(u,0)==1?1:k;
	rep(i,1,lim){
		if(deg(u,i)==2)continue;
		v=adddeg(u,i);
		if(lim==1){
			rep(j,2,k)v=modifypa(v,j,pa(v,j)-1);
			v=(v>>4)|pro(k,size(u),1);
		}else{
			v=(v>>4)|pro(k,pa(u,i),1);
		}
		v=remark(v);
		ins(u,v);t=pa(v,k);
		rep(j,i+1,k){
			if(deg(u,j)==2||t==pa(v,j-1))continue;
			w=adddeg(v,j-1);
			w=adddeg(w,k);
			w=merge(w,t,pa(v,j-1));w=remark(w);
			ins(u,w);
		}
	}
	if(lim!=1){
		v=(u>>4)|pro(k,size(u)+1,0);
		v=remark(v);
		ins(u,v);
	}
}
int now,last;
void boom(int i,int sc,int s){
	if(i>k)f[now][s]++;
	else{
		rep(j,1,i-1)if(deg(s,j)!=2){
			static int u;u=adddeg(s,j);
			boom(i+1,size(u),u|pro(i,pa(s,j),1));
			rep(t,j+1,i-1)if(deg(u,t)!=2){
				if(pa(s,j)==pa(s,t))continue;
				static int v;v=adddeg(u,t);
				v=merge(v,pa(v,j),pa(v,t));
				v|=pro(i,pa(v,j),2);v=remark(v);
				boom(i+1,size(v),v);
			}
		}
		sc++;
		boom(i+1,sc,s|pro(i,sc,0));
	}
}
int main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	while(~scanf("%d%d",&n,&k)){
		if(n==1){puts("1");continue;}
		if(!k){puts("0");continue;}
		tot=0;dfs(1,-1,0);
		now=0;last=1;
		mmt(head,0);cnt=0;
		rep(i,1,tot)find(state[i]);
		mmt(f[now],0);
		boom(1,-1,0);
		rep(node,k+1,n){
			now^=1;last^=1;
			mmt(f[now],0);
			rep(j,1,tot){
				int u=state[j];
				if(!f[last][u])continue;
				int count=0;
				tra(i,u){
					int v=e[i].to;
					(f[now][v]+=f[last][u])%=p;
				}
			}
		}
		int ans=0;
		rep(i,1,tot)if(size(state[i])==0&&f[now][state[i]])
		(ans+=f[now][state[i]])%=p;
		printf("%d\n",ans*2%p);
	}
	return 0;
}


你可能感兴趣的:(HDU 2820 Permutaion)