记录编号 159486 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [CQOI2015]标识设计 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 5.804 s
提交时间 2015-04-21 17:22:44 内存使用 240.64 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
typedef long long LL;
const LL INF=1e18;
const int SIZEN=31,SIZES=4097;
int N,M;
int tot;
char board[SIZEN][SIZEN];
map<int,int> id_lis;
int state[SIZES];
LL F[SIZEN][SIZEN][4][SIZES][2];
int getdig(int s,int i){
	return (s>>i)&1;
}
void add_state(int x){
	id_lis[x]=tot;
	state[tot++]=x;
}
void prepare(void){
	memset(F,-1,sizeof(F));
	add_state(0);
	for(int i=0;i<M-1;i++){
		add_state(1<<i);
		for(int j=i+1;j<M-1;j++){
			add_state((1<<i)|(1<<j));
			for(int k=j+1;k<M-1;k++){
				add_state((1<<i)|(1<<j)|(1<<k));
			}
		}
	}
}
LL DFS(int x,int y,int res,int id,int lim){
	//还有res个L没有放,当前放下的L状态为id,lim为当前格是否需要向右延伸
	LL &ans=F[x][y][res][id][lim];
	if(ans!=-1) return ans;
	int s=state[id];
	ans=0;
	if(x==N) return ans=(!res&&!id)?1:0;
	if(y==M){
		if(lim) return ans=0;
		else return ans=DFS(x+1,0,res,id,0);
	}
	if(getdig(s,y)){//某个L的竖线经过这一列
		if(board[x][y]=='#'||lim) return ans=0;
		else{
			int t=s^(1<<y);
			ans+=DFS(x,y+1,res,id_lis[t],1);//让这个L转而向右
			ans+=DFS(x,y+1,res,id,0);//继续向下什么都不干
			return ans;
		}
	}
	if(lim){//必须放,接着左边的
		if(board[x][y]=='#') return ans=0;
		else return ans=DFS(x,y+1,res,id,1)+DFS(x,y+1,res,id,0);//下一格可以接着放也可以不放
	}
	ans=DFS(x,y+1,res,id,0);//什么也不干......
	if(res>0&&y+1<M&&board[x][y]=='.'){//放下一个L的竖线
		int t=s|(1<<y);
		ans+=DFS(x,y+1,res-1,id_lis[t],0);
	}
	return ans;
}
int main(){
	freopen("cqoi15_logo.in","r",stdin);
	freopen("cqoi15_logo.out","w",stdout);
	scanf("%d%d",&N,&M);
	for(int i=0;i<N;i++) scanf("%s",board[i]);
	prepare();
	LL ans=DFS(0,0,3,0,0);
	cout<<ans<<endl;
	return 0;
}