原题
题目描述
样例
输入
3
3 3
4 5
1 5
输出
Case #1: 3
*.*
...
.*.
Case #2: 6
..*.*
*....
...*.
.*..*
Case #3: 2
.*.*.
思路
如果直接
d
p
dp
dp,三进制表示行的状态:
- 0 0 0表示位置上没人。
- 1 1 1表示位置上有人。
-
2
2
2表示周围有人。
状态数 : : : 3 3 315 = 14348907 ? =14348907? =14348907?这一看就有些不对劲。
所以我们要考虑一下状压 d p dp dp。
去除一些非法的情况 : : : - 两个 0 0 0相邻
- 两个 2 2 2相邻
- 0 0 0的周围有 2 2 2
- 两个相邻的 1 1 1边上没有 2 2 2
状态转移
:
:
:
0
0
0的下一行一定是
2
2
2,
2
2
2的下一行一定是
1
1
1。
因为
T
≤
1000
T≤1000
T≤1000,所以先打表,然后
O
(
1
)
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]);
}