P3693 琪露诺的冰雪小屋 题解
DimensionTripper · · 题解
超级大模拟,简直写的我头疼,但终于还是A掉了,所以来写一篇题解QwQ
首先,我们不管别的,拿20分再说,然后我们发现20分其实挺好拿的啊,瞎jb搞一搞分就来了。以下是20分核心代码:
int num;//这是⑨现在有的冰砖数量
int frz[MAXN][MAXN];//frz数组记录地面的冷冻值,如果有冰砖则为inf
il int Spell_Card(int x,int y,int dir,int s)//弹幕操作,暴力搞就完了
{
int ret=0;
for(ri i=0;i<=s;i++)
{
int Xi,Yi;
switch(dir)
{
case 0:Xi=x-i,Yi=y;break;
case 1:Xi=x-i,Yi=y-i;break;
case 2:Xi=x,Yi=y-i;break;
case 3:Xi=x+i,Yi=y-i;break;
case 4:Xi=x+i,Yi=y;break;
case 5:Xi=x+i,Yi=y+i;break;
case 6:Xi=x,Yi=y+i;break;
case 7:Xi=x-i,Yi=y+i;break;
}
if(Xi<0||Xi>=n||Yi<0||Yi>=n||frz[Xi][Yi]==inf)
break;
else if(frz[Xi][Yi]==4)
continue;
else
{
frz[Xi][Yi]++;
ret++;
}
}
return ret;
}
il int Make()//做冰砖,直接n*n枚举每一块地面就行了
{
int ret=0;
for(ri i=0;i<n;i++)
for(ri j=0;j<n;j++)
if(frz[i][j]==4)
frz[i][j]=0,ret++,num++;
return ret;
}
20分之后,我们会发现30分其实也挺好写的,于是瞎搞一下就又多了10分。以下是30分核心(其实就是PUT_ICE_BLOCK的操作了)
il void Put(int r,int c,int h)
{
if(num==0)
{
printf("CIRNO HAS NO ICE_BLOCK\n");
return;
}
else if(vis[r][c][h]||(h>0&&!vis[r-1][c][h]&&!vis[r+1][c][h]&&!vis[r][c-1][h]&&!vis[r][c+1][h]&&!vis[r][c][h-1]&&!vis[r][c][h+1]))
{
printf("BAKA CIRNO,CAN'T PUT HERE\n");
return;
}
else if(r<Hr||r>Hr+Hx-1||c<Hc||c>Hc+Hy-1)
{
printf("CIRNO MISSED THE PLACE\n");
vis[r][c][h]=1;
num--;
if(h==0)
frz[r][c]=inf;
return;
}
else if(r>=Hr+1&&r<=Hr+Hx-2&&c>=Hc+1&&c<=Hc+Hy-2)
{
printf("CIRNO PUT AN ICE_BLOCK INSIDE THE HOUSE\n");
vis[r][c][h]=1;
num--;
if(h==0)
frz[r][c]=inf;
return;
}
else
{
vis[r][c][h]=1;
num--;
printf("CIRNO SUCCESSFULLY PUT AN ICE_BLOCK,NOW SHE HAS %d ICE_BLOCK(S)\n",num);
if(h==0)
frz[r][c]=inf;
return;
}
}
别看我打得长,其实没多大的思维难度,毕竟出题人很仁慈地把位置位于屋内屋外的判定条件都给出来了,直接抄就行了。
要注意的有两点:
- “可依靠的方块”为上下左右前后六个方向,对没错,上面也可以。
- 一定要判定h=0,即冰砖放在地上的情况,要将
frz[x][y] 修改为inf。 然后就没太大问题了。
30分之后,我们遇到了第一个难题:如何判断悬空联通块。
实际上,如果BFS学的比较熟练的几乎不需要思考,在移除方块之后向6个方向做BFS就完了,如果搜到了h=0的方块,就可以保留,如果搜完了还没有遇到h=0的方块,那么这就是一个悬空联通块了,这个时候所有进过队的方块都要删掉,删掉并统计一下就行了。
以下是50分的核心:
int f[MAXN][MAXN][MAXN];//每个方块所属的联通块
int dx[]={0,0,0,0,1,-1};
int dy[]={0,0,1,-1,0,0};
int dz[]={1,-1,0,0,0,0};
bool vis[MAXN][MAXN][MAXN];
struct node
{
int x,y,z;
};
node q[MAXN];
il bool BFS(int r,int c,int h,int dir)
{
fr=1,tl=0;
q[1]=(node){r,c,h};
f[r][c][h]=dir;
bool flag=0;
while(tl<fr)
{
node u=q[++tl];
if(u.z==0)
flag=1;
for(ri i=0;i<6;i++)
{
node v=(node){u.x+dx[i],u.y+dy[i],u.z+dz[i]};
if(vis[v.x][v.y][v.z]&&f[v.x][v.y][v.z]==-1)
{
q[++fr]=v;
f[v.x][v.y][v.z]=dir;
}
}
}
if(!flag)
for(ri i=1;i<=fr;i++)
vis[q[i].x][q[i].y][q[i].z]=0;//对悬空联通块的处理
return flag;
}
il void Remove(int r,int c,int h)
{
if(!vis[r][c][h])
{
printf("BAKA CIRNO,THERE IS NO ICE_BLOCK\n");
return;
}
else
{
num++,
vis[r][c][h]=0;
if(h==0)
frz[r][c]=0;
memset(f,-1,sizeof(f));
int brk=0;
for(ri i=0;i<6;i++)
{
int R=r+dx[i],C=c+dy[i],H=h+dz[i];
if(f[R][C][H]!=-1||!vis[R][C][H])//对6个方向做BFS
continue;
else if(!BFS(R,C,H,i))
brk+=fr;
else
continue;
}
printf("CIRNO REMOVED AN ICE_BLOCK");
if(brk>0)
printf(",AND %d BLOCK(S) ARE BROKEN",brk);
printf("\n");
}
}
写到这里也许你们会说:这也不是特别难啊,题面又长,还特别水,结果4/5不是一下就打完了吗?然而出题人表示这才刚刚开始呢。
先来看70分,建造屋顶时没有塌陷与方块掉落,也就是说不用BFS,可是我们注意到之前的BFS改造一下就可以放过来用,于是就可以直接冲90分了。
以下是90分部分核心:
il bool BFS(int r,int c,int h,int dir,bool last)
{
fr=1,tl=0;
q[1]=(node){r,c,h};
f[r][c][h]=dir;
bool flag=0;
while(tl<fr)
{
node u=q[++tl];
if(u.z==0)
flag=1;
for(ri i=0;i<6;i++)
{
node v=(node){u.x+dx[i],u.y+dy[i],u.z+dz[i]};
if(vis[v.x][v.y][v.z]&&f[v.x][v.y][v.z]==-1)
{
q[++fr]=v;
f[v.x][v.y][v.z]=dir;
}
}
}
if(!flag)
{
if(!last)
for(ri i=1;i<=fr;i++)
vis[q[i].x][q[i].y][q[i].z]=0;
else
for(ri i=1;i<=fr;i++)
vis[q[i].x][q[i].y][q[i].z]=0,num++;
}
return flag;
}
修改之后的BFS,增加一个last标记,判定是否为MAKE_ROOF时进行的。是,则由于题目条件给出,对悬空联通块中的冰砖进行回收。
bool perfect=1;
il int Get_Height()
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2)
continue;
int h=0;
for(ri k=Hm;k;k--)
if(vis[i][j][k])
{
h=k;
break;
}
ret=max(ret,h);
}
return ret+1;
}//房屋高度
il int Get_Need(int h)
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
if(!vis[i][j][h])
vis[i][j][h]=1,ret++;
return ret;
}
il bool Check_place(int x,int y)
{
if(x==Hr||x==Hr+Hx-1)
{
if(Hy%2)
{
if(y==(Hc+(Hc+Hy-1))/2)
return 1;
}
else
if(y==(Hc+(Hc+Hy-1))/2||y==(Hc+(Hc+Hy-1))/2+1)
return 1;
}
else if(y==Hc||y==Hc+Hy-1)
{
if(Hx%2)
{
if(x==(Hr+(Hr+Hx-1))/2)
return 1;
}
else
if(x==(Hr+(Hr+Hx-1))/2||x==(Hr+(Hr+Hx-1))/2+1)
return 1;
}
return 0;
}//判断一个坐标是否在某面墙的正中间
il bool Check_Door(int &x,int &y)
{
bool flag=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
if(!vis[i][j][0]&&!vis[i][j][1])
{
if((x==-1&&y==-1)||(!Check_place(x,y)&&Check_place(i,j)))
x=i,y=j,flag=1;
}
}
return flag;
}//判断是否有完整的门
il void Get_door_place(int &x,int &y)
{
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
if(!vis[i][j][0]||!vis[i][j][1])
{
if((x==-1&&y==-1)||(!Check_place(x,y)&&Check_place(i,j)))
x=i,y=j;
}
}
}//寻找门的位置
il int Get_need(int x,int y,int h)
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
for(ri k=(i==x&&j==y)?2:0;k<h;k++)
if(!vis[i][j][k])
vis[i][j][k]=1,ret++;
}
return ret;
}//墙上的空缺也是暴力枚举
il int Check_Corner(int h)
{
int ret=0;
for(ri i=0;i<h;i++)
{
if(!vis[Hr][Hc][i])
ret++;
if(!vis[Hr][Hc+Hy-1][i])
ret++;
if(!vis[Hr+Hx-1][Hc][i])
ret++;
if(!vis[Hr+Hx-1][Hc+Hy-1][i])
ret++;
}
return ret;
}//枚举四个角落寻找空缺
il void Fix(int h)
{
bool door=0,corner=0;
int x=-1,y=-1;
door=Check_Door(x,y);//检查是否有完整的门
if(!door)
Get_door_place(x,y);//没有完整的门就寻找只需要拆掉一块冰砖的位置
int need=Get_need(x,y,h);//墙上的空缺
if(num<need)
{
printf("SORRY CIRNO,NOT ENOUGH ICE_BLOCKS TO FIX THE WALL\n");
return;
}
num-=need;
printf("GOOD JOB CIRNO,SUCCESSFULLY BUILT THE HOUSE\n");
if(!door)
printf("HOUSE HAS NO DOOR\n"),perfect=0;
else
printf("DOOR IS OK\n");
if(need>0)
printf("WALL NEED TO BE FIXED\n"),perfect=0;
else
printf("WALL IS OK\n");
need=Check_Corner(h);//角落的空缺
if(need>0)
printf("CORNER NEED TO BE FIXED\n"),perfect=0;
else
printf("CORNER IS OK\n");
if(need>num)
num=0;
else
num-=need;
printf("CIRNO FINALLY HAS %d ICE_BLOCK(S)\n",num);
if(perfect)
printf("CIRNO IS PERFECT!\n");
}
il void Remove_Blocks(int h)
{
memset(f,-1,sizeof(f));
if(!BFS(Hr,Hc,h,0,1))
{
printf("SORRY CIRNO,HOUSE IS BROKEN WHEN REMOVING BLOCKS\n");
return;
}//优先判断屋顶塌陷的情况
int dir=1;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2)
continue;
for(ri k=0;k<h;k++)
if(vis[i][j][k]&&f[i][j][k]==-1)
BFS(i,j,k,dir++,1);
}//回收墙上的悬空联通块
Fix(h);//修复
}
il void Make_Roof()
{
int h=Get_Height();//获取屋顶高度
int need=Get_Need(h);//获取建造屋顶所需数量
if(num<need)
{
printf("SORRY CIRNO,NOT ENOUGH ICE_BLOCK(S) TO MAKE ROOF\n");
return;
}\\砖块不够
int S=(Hx-2)*(Hy-2)*h;//计算内部空间
if(h<2||S<2)
{
printf("SORRY CIRNO,HOUSE IS TOO SMALL\n");
return;
}//空间不足
num-=need;
int num1=0,num2=0;//num1-->屋内|num2-->屋外
for(ri i=Hr+1;i<=Hr+Hx-2;i++)
for(ri j=Hc+1;j<=Hc+Hy-2;j++)
{
for(ri k=0;k<h;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num1++,num++,perfect=0;
for(ri k=h+1;k<Hm;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num2++,num++,perfect=0;//注意,这里是一个大坑。
}//回收屋内冰砖
for(ri i=0;i<n;i++)
for(ri j=0;j<n;j++)
{
if(i>=Hr&&i<=Hr+Hx-1&&j>=Hc&&j<=Hc+Hy-1)
continue;
for(ri k=0;k<Hm;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num2++,num++,perfect=0;
}//回收屋外冰砖
printf("%d ICE_BLOCK(S) INSIDE THE HOUSE NEED TO BE REMOVED\n",num1);
printf("%d ICE_BLOCK(S) OUTSIDE THE HOUSE NEED TO BE REMOVED\n",num2);
Remove_Blocks(h);
}
这样大概就有90-95分了,要注意的是封上屋顶后,高于h的冰砖也算是屋外冰砖了。
然后我们会发现第二组数据非常的奇怪,墙壁上没有空缺标准输出却有WALL NEED TO BE FIXED,而本有空缺的角落却输出了CORNER IS OK。怎么回事呢?数据有问题吗?不是,如果再回去仔细读题会发现题目对墙壁有残缺的定义是“在屋内能看到缺口”,而#2的情况中,门被开在了角落旁边,这样角落的空缺就能被看见了。
那么怎么办?只判定门的位置是否在中间的方法肯定不行了,单独打特判的话绝对会疯掉,毕竟我不想再像出题人那样为10分多打200行。于是我想到了对每个可能作为门的位置进行估价,选取估价较高的位置作为门。
以下是核心部分:
il bool Mid(int x,int y)
{
if(x==Hr||x==Hr+Hx-1)
{
if(Hy%2)
{
if(y==(Hc+(Hc+Hy-1))/2)
return 1;
}
else
if(y==(Hc+(Hc+Hy-1))/2||y==(Hc+(Hc+Hy-1))/2+1)
return 1;
}
else if(y==Hc||y==Hc+Hy-1)
{
if(Hx%2)
{
if(x==(Hr+(Hr+Hx-1))/2)
return 1;
}
else
if(x==(Hr+(Hr+Hx-1))/2||x==(Hr+(Hr+Hx-1))/2+1)
return 1;
}
return 0;
}//这就是之前的Check_door_placeQwQ
il int Corner(int x,int y,bool last)
{
int ret=0;
if((x==Hr&&y==Hc+1)||(x==Hr+1&&y==Hc))
{
for(ri i=0;i<2;i++)
if(!vis[Hr][Hc][i])
{
ret++;
if(last)
vis[Hr][Hc][i]=1;
}
}
if((x==Hr+Hx-1&&y==Hc+1)||(x==Hr+Hc-2&&y==Hc))
{
for(ri i=0;i<2;i++)
if(!vis[Hr+Hx-1][Hc][i])
{
ret++;
if(last)
vis[Hr+Hx-1][Hc][i]=1;
}
}
if((x==Hr&&y==Hc+Hy-2)||(x==Hr+1&&y==Hc+Hy-1))
{
for(ri i=0;i<2;i++)
if(!vis[Hr][Hc+Hy-1][i])
{
ret++;
if(last)
vis[Hr][Hc+Hy-1][i]=1;
}
}
if((x==Hr+Hx-1&&y==Hc+Hy-2)||(x==Hr+Hc-2&&y==Hc+Hy-1))
{
for(ri i=0;i<2;i++)
if(!vis[Hr+Hx-1][Hc+Hy-1][i])
{
ret++;
if(last)
vis[Hr+Hx-1][Hc+Hy-1][i]=1;
}
}
return ret;
}//也是暴力,懒的解释了QwQ
il int Evaluate(int x,int y)
{
int ret=0;
for(ri i=0;i<2;i++)
if(!vis[x][y][i])
ret+=1000;//由于我们优先选择更完整的空隙作为门,所以完整度的估价最高
if(Mid(x,y))
ret+=100;//中间的位置仅次于完整度
int A=Corner(x,y,0);//获取当前位置是否在角落旁边和与其相邻的角落有多少空缺
ret+=((5-A)*10)//空缺越少估价越高;
return ret;
}
il bool Check_Door(int &x,int &y)
{
bool flag=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
if(!vis[i][j][0]||!vis[i][j][1])
{
if((x==-1&&y==-1)||Evaluate(i,j)>Evaluate(x,y))
x=i,y=j,flag=1;
}
}
int E=Evaluate(x,y);
if(flag)
{
if((E/1000)%10==2)
return 1;
return 0;
}//找千位数就可以知道是否完整了
return flag;
}
il int Get_need(int x,int y,int h)
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
for(ri k=(i==x&&j==y)?2:0;k<h;k++)
if(!vis[i][j][k])
vis[i][j][k]=1,ret++;
}
int E=Evaluate(x,y);
ret+=(5-(E/10)%10);
Corner(x,y,1);//如果角落有空缺也要补上
return ret;
}
然后就可以AC了,实际上最后10分也不需要200+排对吧QwQ
以下是完整代码(504排,比出题人写的题解大概少了60排吧,不压行好评QwQ):
#include <bits/stdc++.h>
#define ri register int
#define il inline
#define ll long long
using namespace std;
const int N=2000000+110;
const int inf=0x7fffffff;
const int MAXN=50;
const double eps=1e-8;
il int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
il void Getstr(char ch[])
{
char c=getchar();
int len=-1;
while(c<'A'||c>'Z')
c=getchar();
while((c>='A'&&c<='Z')||c=='_')
{
ch[++len]=c;
c=getchar();
}
}
int n,m,num,fr,tl;
int Hm,Hr,Hc,Hx,Hy;
int frz[MAXN][MAXN],f[MAXN][MAXN][MAXN];
int dx[]={0,0,0,0,1,-1};
int dy[]={0,0,1,-1,0,0};
int dz[]={1,-1,0,0,0,0};
bool perfect=1;
bool vis[MAXN][MAXN][MAXN];
struct node
{
int x,y,z;
};
node q[MAXN];
il int Spell_Card(int x,int y,int dir,int s)
{
int ret=0;
for(ri i=0;i<=s;i++)
{
int Xi,Yi;
switch(dir)
{
case 0:Xi=x-i,Yi=y;break;
case 1:Xi=x-i,Yi=y-i;break;
case 2:Xi=x,Yi=y-i;break;
case 3:Xi=x+i,Yi=y-i;break;
case 4:Xi=x+i,Yi=y;break;
case 5:Xi=x+i,Yi=y+i;break;
case 6:Xi=x,Yi=y+i;break;
case 7:Xi=x-i,Yi=y+i;break;
}
if(Xi<0||Xi>=n||Yi<0||Yi>=n||frz[Xi][Yi]==inf)
break;
else if(frz[Xi][Yi]==4)
continue;
else
{
frz[Xi][Yi]++;
ret++;
}
}
return ret;
}
il int Make()
{
int ret=0;
for(ri i=0;i<n;i++)
for(ri j=0;j<n;j++)
if(frz[i][j]==4)
frz[i][j]=0,ret++,num++;
return ret;
}
il void Put(int r,int c,int h)
{
if(num==0)
{
printf("CIRNO HAS NO ICE_BLOCK\n");
return;
}
else if(vis[r][c][h]||(h>0&&!vis[r-1][c][h]&&!vis[r+1][c][h]&&!vis[r][c-1][h]&&!vis[r][c+1][h]&&!vis[r][c][h-1]&&!vis[r][c][h+1]))
{
printf("BAKA CIRNO,CAN'T PUT HERE\n");
return;
}
else if(r<Hr||r>Hr+Hx-1||c<Hc||c>Hc+Hy-1)
{
printf("CIRNO MISSED THE PLACE\n");
vis[r][c][h]=1;
num--;
if(h==0)
frz[r][c]=inf;
return;
}
else if(r>=Hr+1&&r<=Hr+Hx-2&&c>=Hc+1&&c<=Hc+Hy-2)
{
printf("CIRNO PUT AN ICE_BLOCK INSIDE THE HOUSE\n");
vis[r][c][h]=1;
num--;
if(h==0)
frz[r][c]=inf;
return;
}
else
{
vis[r][c][h]=1;
num--;
printf("CIRNO SUCCESSFULLY PUT AN ICE_BLOCK,NOW SHE HAS %d ICE_BLOCK(S)\n",num);
if(h==0)
frz[r][c]=inf;
return;
}
}
il bool BFS(int r,int c,int h,int dir,bool last)
{
fr=1,tl=0;
q[1]=(node){r,c,h};
f[r][c][h]=dir;
bool flag=0;
while(tl<fr)
{
node u=q[++tl];
if(u.z==0)
flag=1;
for(ri i=0;i<6;i++)
{
node v=(node){u.x+dx[i],u.y+dy[i],u.z+dz[i]};
if(vis[v.x][v.y][v.z]&&f[v.x][v.y][v.z]==-1)
{
q[++fr]=v;
f[v.x][v.y][v.z]=dir;
}
}
}
if(!flag)
{
if(!last)
for(ri i=1;i<=fr;i++)
vis[q[i].x][q[i].y][q[i].z]=0;
else
for(ri i=1;i<=fr;i++)
vis[q[i].x][q[i].y][q[i].z]=0,num++;
}
return flag;
}
il void Remove(int r,int c,int h)
{
if(!vis[r][c][h])
{
printf("BAKA CIRNO,THERE IS NO ICE_BLOCK\n");
return;
}
else
{
num++,
vis[r][c][h]=0;
if(h==0)
frz[r][c]=0;
memset(f,-1,sizeof(f));
int brk=0;
for(ri i=0;i<6;i++)
{
int R=r+dx[i],C=c+dy[i],H=h+dz[i];
if(f[R][C][H]!=-1||!vis[R][C][H])
continue;
else if(!BFS(R,C,H,i,0))
brk+=fr;
else
continue;
}
printf("CIRNO REMOVED AN ICE_BLOCK");
if(brk>0)
printf(",AND %d BLOCK(S) ARE BROKEN",brk);
printf("\n");
}
}
il int Get_Height()
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2)
continue;
int h=0;
for(ri k=Hm;k;k--)
if(vis[i][j][k])
{
h=k;
break;
}
ret=max(ret,h);
}
return ret+1;
}
il int Get_Need(int h)
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
if(!vis[i][j][h])
vis[i][j][h]=1,ret++;
return ret;
}
il bool Mid(int x,int y)
{
if(x==Hr||x==Hr+Hx-1)
{
if(Hy%2)
{
if(y==(Hc+(Hc+Hy-1))/2)
return 1;
}
else
if(y==(Hc+(Hc+Hy-1))/2||y==(Hc+(Hc+Hy-1))/2+1)
return 1;
}
else if(y==Hc||y==Hc+Hy-1)
{
if(Hx%2)
{
if(x==(Hr+(Hr+Hx-1))/2)
return 1;
}
else
if(x==(Hr+(Hr+Hx-1))/2||x==(Hr+(Hr+Hx-1))/2+1)
return 1;
}
return 0;
}
il int Corner(int x,int y,bool last)
{
int ret=0;
if((x==Hr&&y==Hc+1)||(x==Hr+1&&y==Hc))
{
for(ri i=0;i<2;i++)
if(!vis[Hr][Hc][i])
{
ret++;
if(last)
vis[Hr][Hc][i]=1;
}
}
if((x==Hr+Hx-1&&y==Hc+1)||(x==Hr+Hc-2&&y==Hc))
{
for(ri i=0;i<2;i++)
if(!vis[Hr+Hx-1][Hc][i])
{
ret++;
if(last)
vis[Hr+Hx-1][Hc][i]=1;
}
}
if((x==Hr&&y==Hc+Hy-2)||(x==Hr+1&&y==Hc+Hy-1))
{
for(ri i=0;i<2;i++)
if(!vis[Hr][Hc+Hy-1][i])
{
ret++;
if(last)
vis[Hr][Hc+Hy-1][i]=1;
}
}
if((x==Hr+Hx-1&&y==Hc+Hy-2)||(x==Hr+Hc-2&&y==Hc+Hy-1))
{
for(ri i=0;i<2;i++)
if(!vis[Hr+Hx-1][Hc+Hy-1][i])
{
ret++;
if(last)
vis[Hr+Hx-1][Hc+Hy-1][i]=1;
}
}
return ret;
}
il int Evaluate(int x,int y)
{
int ret=0;
for(ri i=0;i<2;i++)
if(!vis[x][y][i])
ret+=1000;
if(Mid(x,y))
ret+=100;
int A=Corner(x,y,0);
ret+=((5-A)*10);
return ret;
}
il bool Check_Door(int &x,int &y)
{
bool flag=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
if(!vis[i][j][0]||!vis[i][j][1])
{
if((x==-1&&y==-1)||Evaluate(i,j)>Evaluate(x,y))
x=i,y=j,flag=1;
}
}
int E=Evaluate(x,y);
if(flag)
{
if((E/1000)%10==2)
return 1;
return 0;
}
return flag;
}
il int Get_need(int x,int y,int h)
{
int ret=0;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if((i==Hr&&j==Hc)||(i==Hr&&j==Hc+Hy-1)||(i==Hr+Hx-1&&j==Hc)||(i==Hr+Hx-1&&j==Hc+Hy-1)||(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2))
continue;
for(ri k=(i==x&&j==y)?2:0;k<h;k++)
if(!vis[i][j][k])
vis[i][j][k]=1,ret++;
}
int E=Evaluate(x,y);
ret+=(5-(E/10)%10);
Corner(x,y,1);
return ret;
}
il int Check_Corner(int h)
{
int ret=0;
for(ri i=0;i<h;i++)
{
if(!vis[Hr][Hc][i])
ret++;
if(!vis[Hr][Hc+Hy-1][i])
ret++;
if(!vis[Hr+Hx-1][Hc][i])
ret++;
if(!vis[Hr+Hx-1][Hc+Hy-1][i])
ret++;
}
return ret;
}
il void Fix(int h)
{
bool door=0,corner=0;
int x=-1,y=-1;
door=Check_Door(x,y);
if(x!=-1&&y!=-1)
{
int E=Evaluate(x,y);
num+=(2-(E/1000)%10);
}
else
num+=2;
int need=Get_need(x,y,h);
if(num<need)
{
printf("SORRY CIRNO,NOT ENOUGH ICE_BLOCKS TO FIX THE WALL\n");
return;
}
num-=need;
printf("GOOD JOB CIRNO,SUCCESSFULLY BUILT THE HOUSE\n");
if(!door)
printf("HOUSE HAS NO DOOR\n"),perfect=0;
else
printf("DOOR IS OK\n");
if(need>0)
printf("WALL NEED TO BE FIXED\n"),perfect=0;
else
printf("WALL IS OK\n");
need=Check_Corner(h);
if(need>0)
printf("CORNER NEED TO BE FIXED\n"),perfect=0;
else
printf("CORNER IS OK\n");
if(need>num)
num=0;
else
num-=need;
printf("CIRNO FINALLY HAS %d ICE_BLOCK(S)\n",num);
if(perfect)
printf("CIRNO IS PERFECT!\n");
}
il void Remove_Blocks(int h)
{
memset(f,-1,sizeof(f));
if(!BFS(Hr,Hc,h,0,1))
{
printf("SORRY CIRNO,HOUSE IS BROKEN WHEN REMOVING BLOCKS\n");
return;
}
int dir=1;
for(ri i=Hr;i<=Hr+Hx-1;i++)
for(ri j=Hc;j<=Hc+Hy-1;j++)
{
if(i>=Hr+1&&i<=Hr+Hx-2&&j>=Hc+1&&j<=Hc+Hy-2)
continue;
for(ri k=0;k<h;k++)
if(vis[i][j][k]&&f[i][j][k]==-1)
BFS(i,j,k,dir++,1);
}
Fix(h);
}
il void Make_Roof()
{
int h=Get_Height();
int need=Get_Need(h);
if(num<need)
{
printf("SORRY CIRNO,NOT ENOUGH ICE_BLOCK(S) TO MAKE ROOF\n");
return;
}
int S=(Hx-2)*(Hy-2)*h;
if(h<2||S<2)
{
printf("SORRY CIRNO,HOUSE IS TOO SMALL\n");
return;
}
num-=need;
int num1=0,num2=0;
for(ri i=Hr+1;i<=Hr+Hx-2;i++)
for(ri j=Hc+1;j<=Hc+Hy-2;j++)
{
for(ri k=0;k<h;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num1++,num++,perfect=0;
for(ri k=h+1;k<Hm;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num2++,num++,perfect=0;
}
for(ri i=0;i<n;i++)
for(ri j=0;j<n;j++)
{
if(i>=Hr&&i<=Hr+Hx-1&&j>=Hc&&j<=Hc+Hy-1)
continue;
for(ri k=0;k<Hm;k++)
if(vis[i][j][k])
vis[i][j][k]=0,num2++,num++,perfect=0;
}
printf("%d ICE_BLOCK(S) INSIDE THE HOUSE NEED TO BE REMOVED\n",num1);
printf("%d ICE_BLOCK(S) OUTSIDE THE HOUSE NEED TO BE REMOVED\n",num2);
Remove_Blocks(h);
}
int main()
{
n=read();
Hm=read();
Hr=read(),Hc=read(),Hx=read(),Hy=read();
m=read();
for(ri i=1;i<=m;i++)
{
char opt[MAXN];
memset(opt,0,sizeof(opt));
Getstr(opt);
if(strcmp(opt,"ICE_BARRAGE")==0)
{
int r=read(),c=read(),dir=read(),s=read();
printf("CIRNO FREEZED %d BLOCK(S)\n",Spell_Card(r,c,dir,s));
}
else if(strcmp(opt,"MAKE_ICE_BLOCK")==0)
{
int k=Make();
printf("CIRNO MADE %d ICE BLOCK(S),NOW SHE HAS %d ICE BLOCK(S)\n",k,num);
}
else if(strcmp(opt,"PUT_ICE_BLOCK")==0)
{
int r=read(),c=read(),h=read();
Put(r,c,h);
}
else if(strcmp(opt,"REMOVE_ICE_BLOCK")==0)
{
int r=read(),c=read(),h=read();
Remove(r,c,h);
}
else
Make_Roof();
}
return 0;
}