020牛客暑期多校训练营(第八场)Cinema

原题
题目描述
在这里插入图片描述
样例
输入

3
3 3
4 5
1 5

输出

Case #1: 3
*.*
...
.*.
Case #2: 6
..*.*
*....
...*.
.*..*
Case #3: 2
.*.*.

思路
如果直接 d p dp ,三进制表示行的状态:

  • 0 0 表示位置上没人。
  • 1 1 表示位置上有人。
  • 2 2 表示周围有人。
    状态数 3 3 15 = 14348907 ? =14348907? 这一看就有些不对劲。
    所以我们要考虑一下状压 d p dp
    去除一些非法的情况
  • 两个 0 0 相邻
  • 两个 2 2 相邻
  • 0 0 的周围有 2 2
  • 两个相邻的 1 1 边上没有 2 2

状态转移
0 0 的下一行一定是 2 2 2 2 的下一行一定是 1 1
因为 T 1000 T≤1000 ,所以先打表,然后 O ( 1 ) O(1) 查询。
代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node
{
	int f,s;
	node(){}node(int _f,int _s){f=_f,s=_s;}
	bool operator<(const node &n1)const{return f<n1.f;}
};
const int maxm=16,maxx=1005,maxn=6600,maxxn=13e6+5;
int q[maxx],st[maxn],id[maxxn],dp[maxx][maxn],p[maxx][maxn],num2[maxn],num1[maxn],ans[maxn],a[maxn],tot,t,n,m;
vector<node>vec[maxn];
vector<int>nt[maxn],s[maxn];
void dfs(int pos,int now,int mm)
{
	if(pos==mm)
	{
		if(pos>=2&&(now%3==1)&&(now/3%3==1)&&(pos-2<0||now/9%3!=2))return;
		id[now]=tot;st[tot++]=now;return;
	}
	if(!pos){dfs(pos+1,now*3,mm);dfs(pos+1,now*3+1,mm);dfs(pos+1,now*3+2,mm);return;}
	if(now%3^1){dfs(pos+1,now*3+1,mm);return;}
	dfs(pos+1,now*3+2,mm);
	if(!(pos>=2&&(now%3==1)&&now/3%3==1&&(pos-2<0||now/9%3!=2)))dfs(pos+1,now*3,mm),dfs(pos+1,now*3+1,mm);
}
int get2(int x)
{
	int ret=0;
	while(x){if(x%3==2)ret++;x/=3;}
	return ret;
}
int get1(int x,int mm)
{
	int ret=0;
	for(int i=0;i<mm;i++){if(x%3==0)ret++;x/=3;}
	return ret;
}
void search(vector<int> &res,int a[],int mm,int now,int pos)
{
	if(pos>=mm){res.push_back(now);return;}
	if(a[pos]==2)search(res,a,mm,now*3+1,pos+1);
	else if(!a[pos])
	{
		if(pos+1<mm)search(res,a,mm,(now*3+2)*3+1,pos+2);
		else search(res,a,mm,now*3+2,pos+1);
	}
	else
		if(pos+1<mm)
		{
			if(!a[pos+1])search(res,a,mm,now*3+1,pos+1);
			else if(a[pos+1]==2)search(res,a,mm,now*3,pos+1),search(res,a,mm,now*3+2,pos+1);
			else
			{
				if(pos+2>=mm||a[pos+2]==2)search(res,a,mm,(now*3+2)*3+1,pos+2),search(res,a,mm,(now*3+1)*3+2,pos+2);
				else if(!a[pos+2])search(res,a,mm,now*9+1,pos+2),search(res,a,mm,(now*3+2)*3+1,pos+2);
				else if(pos+3>=mm||a[pos+3]==2)search(res,a,mm,(now*3+2)*3+1,pos+2),search(res,a,mm,(now*9+1)*3+2,pos+3),search(res,a,mm,((now*3+1)*3+2)*3+1,pos+3);
			}
			
		}
		else search(res,a,mm,now*3,pos+1),search(res,a,mm,now*3+2,pos+1);
}
bool check(int x,int mm)
{
	int a[maxn];
	for(int i=0;i<mm;i++)a[i]=x%3,x/=3;
	for(int i=0;i<mm;i++)if(a[i]==1&&(!i||a[i-1]!=2)&&(i==mm-1||a[i+1]!=2))return false;
	return true;
}
void solve(vector<node> qu,int mm)
{
	int len=qu.size(),qd=0;
	if(!len)return;
	sort(qu.begin(),qu.end());tot=0;dfs(0,0,mm);
	for(int i=0,ts;i^tot;i++)
	{
		num2[i]=get2(st[i]);num1[i]=get1(st[i],mm);nt[i].clear();ts=st[i];
		for(int j=mm-1;j>=0;j--)a[j]=ts%3,ts/=3;
		search(nt[i],a,mm,0,0);
	}
	memset(dp,-1,sizeof(dp));
	for(int i=0;i^tot;i++)if(check(st[i],mm))dp[1][i]=num2[i];
	for(int i=1;i<=maxx-5;i++)
	{
		while(qd<len&&qu[qd].f==i)
		{
			int qn=qu[qd].s;
			ans[qn]=i*mm;s[qn].clear();int tmp=-1;
			for(int j=0;j<tot;j++)if(dp[i][j]!=-1&&ans[qn]>dp[i][j]+num1[j])tmp=j,ans[qn]=dp[i][j]+num1[j];
			s[qn].push_back(st[tmp]);
			for(int j=i;j^1;j--)tmp=p[j][tmp],s[qn].push_back(st[tmp]);
			qd++;
		}
		if(qd==len)break;
		for(int j=0;j^tot;j++)
		{
			if(dp[i][j]==-1)continue;
			for(int k=0,v,idd;k^nt[j].size();k++)
			{
				v=nt[j][k];idd=id[v];
				if(dp[i+1][idd]==-1||dp[i+1][idd]>dp[i][j]+num2[idd])dp[i+1][idd]=dp[i][j]+num2[idd],p[i+1][idd]=j;
			}
		}
	}
}
void sc(vector<int> ve,int mm)
{
	for(int i=ve.size()-1,v;i>=0;i--)
	{
		v=ve[i];
		for(int j=0;j<mm;j++)
		{
			if(v%3==2||(!i&&v%3==0))printf("*");
			else printf(".");
			v/=3;
		}
		printf("\n");
	}
}
int main()
{
	for(int i=1;i^maxm;i++)vec[i].clear();
	scanf("%d",&t);
	for(int i=0;i^t;i++)scanf("%d%d",&n,&m),vec[m].push_back(node(n,i)),q[i]=m;
	for(int i=1;i^maxm;i++)solve(vec[i],i);
	for(int Case=0;Case^t;++Case)printf("Case #%d: %d\n",Case+1,ans[Case]),sc(s[Case],q[Case]);
}

猜你喜欢

转载自blog.csdn.net/bbbll123/article/details/107889206