P7689 [CEOI2002] Bugs Integrated,Inc.

link

极好的状压DP,提供了一种状压的写法。

令人难受的是这道题由于芯片可能会占据三行的空间,所以要用到三进制,而由于某些不可抗因素三进制是不能直接使用位运算来取出的。然后就考虑用 \(f[i][j]\) 来代表第 i 行状态是 j 方案数。这样显然会超时,但一个显然的优化是每一行的合法状态是不多的,毕竟既要保证不占到障碍,不和前一行向前凸的地方冲突,还要保证芯片的形状合格。满足这些条件是需要搜索的,题解提供了一种写起来很舒服的写法,边搜索边更新答案,每搜索到边界就代表获得了一个合法的状态,用之前的状态来更新当前状态即可,还是比较巧妙的。

#include<bits/stdc++.h>
//#define feyn
const int N=100010;
const int S=60;
const int M=15;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}
inline int max(int s1,int s2){
	return s1<s2?s2:s1;
}

int m,n,num,g[2][N],p[M],ans;
bool a[S*10][S];
inline int q(int wh,int pl){
	return wh/p[pl-1]%3;
}
inline bool able(int wh,int pl,int last){
	if(pl>n)return false;
	return a[wh][pl]==false&&q(last,pl)==0;
}
inline void f(int wh,int pl,int now,int last,int put){
	//第wh行,第pl个,本行now,上一行last,已经放置put个 
	bool t=wh&1;int data;
	if(pl>n){
		g[t][now]=max(g[t][now],g[t^1][last]+put);
		return;
	}
	if(data=q(last,pl)){
		if(a[wh][pl])return;
		f(wh,pl+1,now+(data-1)*p[pl-1],last,put);
		return;
	}
	f(wh,pl+1,now,last,put);
	if(able(wh,pl,last)&&able(wh,pl+1,last)){
		f(wh,pl+2,now+2*(p[pl-1]+p[pl]),last,put+1);
		if(able(wh,pl+2,last)){
			f(wh,pl+3,now+p[pl-1]+p[pl]+p[pl+1],last,put+1);
		}
	}
	return;
}
inline void solve(){
	memset(a,false,sizeof(a));
	memset(g,0xcf,sizeof(g));
	ans=0;
	
	read(m);read(n);read(num);
	int s1,s2;
	while(num--){
		read(s1);read(s2);a[s1][s2]=true;
	}
	
	g[0][0]=0;
	for(int i=1;i<=m;i++){
		memset(g[i&1],0xcf,sizeof(g[i&1]));
		for(int j=0;j<p[n];j++){
			if(g[i+1&1][j]>=0){
				f(i,1,0,j,0);
			}
		}
	}
	printf("%d\n",g[m&1][0]);
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	p[0]=1;for(int i=1;i<=12;i++)p[i]=p[i-1]*3;
	int T;read(T);
	while(T--)solve();
	
	return 0;
}
posted @ 2022-07-14 16:12  Feyn618  阅读(15)  评论(0编辑  收藏  举报