zoukankan      html  css  js  c++  java
  • UOJ#39. 【清华集训2014】简单回路 动态规划 插头DP

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ39.html

    前言

    老年选手没有码力。太久没更博了强行更一发。

    题解

    这题一看就是个插头DP,于是我们考虑用括号序列来表示状态。

    关于插头DP,推荐一篇博客:https://www.cnblogs.com/zinthos/p/3897854.html

    我们发现,(m=6) 时,不同的插头状态数只有 (C_1inom 62 + C_2inom 64 + C_3 inom 66 = 50) 个。(其中 (C_x)(x) 对括号组成的可能的括号序列数)

    (pre_{i,S}) 表示前 (i) 行,没有闭环,第 (i) 行的插头情况为 (S) 的方案数。

    (suf_{i,S}) 表示后 (n-i+1) 行,没有闭环,第 (i) 行的插头情况为 (S) 的方案数。

    (ans_{i,j}) 表示 ((i,j))((i+1,j)) 之间的竖边的答案。

    那么,假设 (S,T) 是一对拼在一起刚好是一个环的插头状态,那么,如果 ((i,j)leftrightarrow (i+1,j)) 是某 (S,T) 的插头衔接处的竖边,那么 (ans_{i,j}) 就包含了相应的 (pre_{i,S}cdot suf_{i+1,T}) 种方案。

    接下来考虑如何求 (pre)(suf)

    考虑预处理转移,设当前插头为 (S),枚举新的一行中有哪些横边被经过,然后计算出转移到的状态即可。

    具体实现过于复杂,只能用 (s** t) 来形容。

    代码

    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=(a);i<=(b);i++)
    #define Fod(i,b,a) for (int i=(b);i>=(a);i--)
    #define fi first
    #define se second
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    using namespace std;
    typedef long long LL;
    typedef pair <int,int> pii;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=1005,M=10,S=55,mod=1e9+7;
    void Add(int &x,int y){
    	if ((x+=y)>=mod)
    		x-=mod;
    }
    int n,m;
    int a[N];
    void in_a(){
    	int k=read(),x,y;
    	while (k--)
    		x=read(),y=read(),a[x]|=1<<y;
    }
    int id[N],val[S][M],scnt=0,can[S];
    vector <pii> trans[S];
    vector <int> opp[S];
    void getmatch(int *s,int *p){
    	static int st[M];
    	int top=0;
    	For(i,1,m)
    		if (s[i]==1)
    			st[++top]=i;
    		else if (s[i]==-1)
    			p[i]=st[top],p[st[top]]=i,top--;
    }
    void get_trans(int x,int e){
    	static int f[M],p[M],d[M],res[M],vis[M];
    	clr(f),clr(p),clr(res),clr(vis);
    	int *s=val[x];
    	For(i,1,m-1)
    		f[i]=e>>(i-1)&1;
    	int zzy=0;
    	For(i,1,m){
    		d[i]=(s[i]!=0)+f[i-1]+f[i];
    		if (s[i]!=0&&f[i-1]&&f[i])
    			return;
    		if (d[i])
    			zzy|=1<<i;
    	}
    	getmatch(s,p);
    	For(i,1,m){
    		if (vis[i]||d[i]!=1)
    			continue;
    		int j=i;
    		while (j==i||d[j]==2){
    			int nxt=0;
    			vis[j]=1;
    			if (p[j]&&!vis[p[j]])
    				nxt=p[j];
    			else if (f[j-1]&&!vis[j-1])
    				nxt=j-1;
    			else if (f[j]&&!vis[j+1])
    				nxt=j+1;
    			if (!nxt)
    				return;
    			j=nxt;
    		}
    		vis[j]=1;
    		res[min(i,j)]=1,res[max(i,j)]=-1;
    	}
    	For(i,1,m)
    		if (d[i]&&!vis[i])
    			return;
    	int Res=0;
    	Fod(i,m,1)
    		Res=Res*3+res[i]+1;
    	trans[x].pb(mp(id[Res],zzy));
    }
    int check_opposite(int *a,int *b){
    	static int pa[M],pb[M],vis[M];
    	clr(vis);
    	For(i,1,m)
    		if ((a[i]!=0)^(b[i]!=0))
    			return 0;
    	getmatch(a,pa),getmatch(b,pb);
    	int cnt=0;
    	For(i,1,m)
    		if (a[i]!=0)
    			cnt++;
    	For(i,1,m)
    		if (a[i]!=0){
    			int x=i;
    			For(t,1,cnt){
    				vis[x]=1,x=(t&1?pa:pb)[x];
    				if (t<cnt&&vis[x])
    					return 0;
    			}
    			return 1;
    		}
    }
    void getval(int m){
    	static int tmp[M];
    	int p3=pow(3,m);
    	For(i,0,p3-1){
    		clr(tmp);
    		int t=i,s=0,flag=1,empty=1,Can=0;
    		For(j,1,m){
    			tmp[j]=t%3-1;
    			if (s==1&&Can!=-1)
    				Can|=1<<j;
    			s+=tmp[j];
    			if (s==1&&Can!=-1)
    				Can|=1<<j;
    			if (s>1)
    				Can=-1;
    			empty&=s==0;
    			flag&=s>=0;
    			t/=3;
    		}
    		flag&=s==0;
    		flag&=!empty;
    		if (flag){
    			id[i]=++scnt;
    			For(j,1,m)
    				val[scnt][j]=tmp[j];
    			can[scnt]=Can;
    		}
    	}
    	For(i,1,scnt){
    		For(e,0,(1<<(m-1))-1)
    			get_trans(i,e);
    		For(j,1,scnt)
    			if (check_opposite(val[i],val[j]))
    				opp[i].pb(j);
    	}
    }
    int pre[N][S],suf[N][S];
    int ans[N][M];
    int main(){
    	n=read(),m=read();
    	in_a();
    	getval(m);
    	For(i,1,n){
    		For(j,1,scnt){
    			if (can[j]!=-1&&!(can[j]&a[i]))
    				Add(pre[i][j],1);
    			int v=pre[i-1][j];
    			if (!v)
    				continue;
    			for (auto t : trans[j])
    				if (!(t.se&a[i]))
    					Add(pre[i][t.fi],v);
    		}
    	}
    	Fod(i,n,1){
    		For(j,1,scnt){
    			if (can[j]!=-1&&!(can[j]&a[i]))
    				Add(suf[i][j],1);
    			int v=suf[i+1][j];
    			if (!v)
    				continue;
    			for (auto t : trans[j])
    				if (!(t.se&a[i]))
    					Add(suf[i][t.fi],v);
    		}
    	}
    	For(i,1,n-1)
    		For(j,1,scnt)
    			for (auto o : opp[j]){
    				int v=(LL)pre[i][j]*suf[i+1][o]%mod;
    				For(k,1,m)
    					if (val[j][k]!=0)
    						Add(ans[i][k],v);
    			}
    	int q=read();
    	while (q--){
    		int x=read(),y=read();
    		printf("%d
    ",ans[x][y]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java如何编写自动售票机程序
    install windows service
    redis SERVER INSTALL WINDOWS SERVICE
    上传文件
    This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.
    解决Uploadify上传控件加载导致的GET 404 Not Found问题
    OracleServiceORCL服务不见了怎么办
    Access to the temp directory is denied. Identity 'NT AUTHORITYNETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss
    MSSQL Server 2008 数据库安装失败
    数据库数据导出成XML文件
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ39.html
Copyright © 2011-2022 走看看