题目大意:琪露诺的冰雪小屋,我做的第一道大模拟题。

题解:模拟。。。

卡点:无数小错误,要是没有写一点调一点,那大概是永远调不出来了。。。

C++ Code:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <queue>
  4. #include <cstdlib>
  5. #define PutRe(x) {puts(x); return ;}
  6. inline int min(int a, int b) {return a < b ? a : b;}
  7. inline int max(int a, int b) {return a > b ? a : b;}
  8. namespace snow_house {
  9. #define MAXN 17
  10. #define MAXH 21
  11. const int __X[8] = {-1, -1, 0, 1, 1, 1, 0, -1},
  12. __Y[8] = {0, -1, -1, -1, 0, 1, 1, 1};
  13. //0.上 1.左上 2.左 3.左下 4.下 5.右下 6.右 7.右上
  14. /*
  15. x-1,y-1 x-1,y x-1,y+1
  16. x,y-1 x,y x,y+1
  17. x+1,y-1 x+1,y x+1,y+1
  18. */
  19.  
  20. int n, HM, m, Tim;
  21. int HR, HC, HX, HY, Height; //左上角位置,长度,宽度,房顶高度
  22.  
  23. int Ice_Block_Num; //剩余方块数
  24.  
  25. int Frozen_Value[MAXN][MAXN]; //地面冷冻值
  26. bool Block[MAXN][MAXN][MAXH]; //是否有方块
  27.  
  28. inline bool over_range(int x, int y) {return x < 0 || y < 0 || x >= n || y >= n;}
  29. inline bool over_range(int x, int y, int z) {return over_range(x, y) || z < 0 || z > HM;}
  30.  
  31. void ice_barrage(int R, int C, int D, int S) { //发射冰雪弹幕
  32. int k = 0;
  33. for (int i = 0; i <= S; i++) {
  34. if (Block[R][C][0]) break;
  35. if (Frozen_Value[R][C] < 4) Frozen_Value[R][C]++, k++;
  36. R += __X[D], C += __Y[D];
  37. if (over_range(R, C)) break;
  38. }
  39. printf("CIRNO FREEZED %d BLOCK(S)", k);
  40. if (Tim != m) puts("");
  41. }
  42.  
  43. void make_ice_block() { //造冰砖
  44. int cnt = 0;
  45. for (int i = 0; i < n; i++) {
  46. for (int j = 0; j < n; j++) if (Frozen_Value[i][j] == 4) {
  47. Frozen_Value[i][j] = 0;
  48. cnt++;
  49. }
  50. }
  51. Ice_Block_Num += cnt;
  52. printf("CIRNO MADE %d ICE BLOCK(S),NOW SHE HAS %d ICE BLOCK(S)\n", cnt, Ice_Block_Num);
  53. }
  54.  
  55. const int Space_X[6] = {1, -1, 0, 0, 0, 0},
  56. Space_Y[6] = {0, 0, 1, -1, 0, 0},
  57. Space_Z[6] = {0, 0, 0, 0, 1, -1};
  58.  
  59. bool can_put(int R, int C, int H) { //是否可以放冰砖(即六个方向有冰砖且此位置没有冰砖)
  60. if (Block[R][C][H]) return false;
  61. if (H == 0) return true;
  62. for (int i = 0; i < 6; i++) {
  63. int x = R + Space_X[i], y = C + Space_Y[i], z = H + Space_Z[i];
  64. if (over_range(x, y, z)) continue;
  65. if (Block[x][y][z]) return true;
  66. }
  67. return false;
  68. }
  69.  
  70. inline bool outside(int R, int C) {return R < HR || R >= HR + HX || C < HC || C >= HC + HY;}
  71. inline bool inside(int R, int C) {return HR + 1 <= R && R <= HR + HX - 2 && HC + 1 <= C && C <= HC + HY - 2;}
  72.  
  73. void put_ice_block(int R, int C, int H) { //放冰砖
  74. if (!Ice_Block_Num) PutRe("CIRNO HAS NO ICE_BLOCK")
  75. if (!can_put(R, C, H)) PutRe("BAKA CIRNO,CAN'T PUT HERE")
  76. Block[R][C][H] = true; Ice_Block_Num--;
  77. if (H == 0) Frozen_Value[R][C] = 0;
  78.  
  79. if (outside(R, C)) PutRe("CIRNO MISSED THE PLACE")
  80. if (inside(R, C)) PutRe("CIRNO PUT AN ICE_BLOCK INSIDE THE HOUSE")
  81. printf("CIRNO SUCCESSFULLY PUT AN ICE_BLOCK,NOW SHE HAS %d ICE_BLOCK(S)\n", Ice_Block_Num);
  82. }
  83.  
  84. struct point {
  85. int x, y, z;
  86. inline point(int __x = 0, int __y = 0, int __z = 0) {x = __x, y = __y, z = __z;}
  87. };
  88.  
  89. bool vis[MAXN][MAXN][MAXH];
  90.  
  91. int fall_block(int R, int C, int H) { //计算会掉下来多少个冰砖
  92. if (over_range(R, C, H) || !Block[R][C][H]) return 0;
  93. memset(vis, false, sizeof vis);
  94. std::queue<point> q; while (!q.empty()) q.pop();
  95. bool Fallen = true; //判断这个连通块是否有冰砖接地(即是否会掉下)
  96. int cnt = 0;
  97.  
  98. q.push(point(R, C, H)); vis[R][C][H] = true;
  99. while (!q.empty()) {
  100. point u = q.front(); q.pop();
  101. if (u.z == 0) {
  102. Fallen = false;
  103. break;
  104. }
  105. for (int i = 0; i < 6; i++) {
  106. int x = u.x + Space_X[i], y = u.y + Space_Y[i], z = u.z + Space_Z[i];
  107. if (over_range(x, y, z) || vis[x][y][z] || !Block[x][y][z]) continue;
  108. vis[x][y][z] = true;
  109. q.push(point(x, y, z));
  110. }
  111. }
  112. if (Fallen) {
  113. for (int i = 0; i < n; i++) {
  114. for (int j = 0; j < n; j++) {
  115. for (int k = 0; k < HM; k++) if (vis[i][j][k]) {
  116. Block[i][j][k] = false;
  117. cnt++;
  118. }
  119. }
  120. }
  121. }
  122. return cnt;
  123. }
  124.  
  125. void remove_ice_block(int R, int C, int H, bool echo = true) { //移除冰砖,echo:是否输出(若为false即为造屋顶阶段,掉落的方块会被回收)
  126. if (!Block[R][C][H]) {
  127. if (echo) PutRe("BAKA CIRNO,THERE IS NO ICE_BLOCK")
  128. return ;
  129. }
  130. Block[R][C][H] = false; Ice_Block_Num++;
  131. int k = 0;
  132. for (int i = 0; i < 6; i++) k += fall_block(R + Space_X[i], C + Space_Y[i], H + Space_Z[i]);
  133. if (!echo) Ice_Block_Num += k;
  134.  
  135. if (echo) {
  136. if (!k) puts("CIRNO REMOVED AN ICE_BLOCK");
  137. else printf("CIRNO REMOVED AN ICE_BLOCK,AND %d BLOCK(S) ARE BROKEN\n", k);
  138. }
  139. }
  140.  
  141. int get_max_height(int x, int y) { //求出该点最高的方块高度
  142. int res = -1;
  143. for (int i = 0; i < HM; i++) if (Block[x][y][i]) res = i;
  144. return res;
  145. }
  146.  
  147. int get_roof_height() { //求屋顶的高度
  148. int res = -1;
  149. for (int i = 0; i < HX; i++) {
  150. res = max(res, get_max_height(HR + i, HC));
  151. res = max(res, get_max_height(HR + i, HC + HY - 1));
  152. }
  153. for (int i = 1; i < HY - 1; i++) {
  154. res = max(res, get_max_height(HR, HC + i));
  155. res = max(res, get_max_height(HR + HX - 1, HC + i));
  156. }
  157. return res + 1;
  158. }
  159.  
  160. int calc_block_num(int X_1, int Y_1, int X_2, int Y_2, int H) { //计算高度为H的平面中给定区间的方块数
  161. int res = 0;
  162. for (int i = X_1; i <= X_2; i++) {
  163. for (int j = Y_1; j <= Y_2; j++) {
  164. res += Block[i][j][H];
  165. }
  166. }
  167. return res;
  168. }
  169.  
  170. inline bool outside(int x, int y, int z) {return outside(x, y) || z > Height;}
  171. inline bool inside(int x, int y, int z) {return inside(x, y) && z < Height;}
  172.  
  173. int Inside_Block_Num, Outside_Block_Num;
  174. void calc_rest_of_block_num() { //计算屋内和屋外的方块数
  175. for (int i = 0; i < n; i++) {
  176. for (int j = 0; j < n; j++) {
  177. for (int k = 0; k <= HM; k++) if (Block[i][j][k]) {
  178. Inside_Block_Num += inside(i, j, k);
  179. Outside_Block_Num += outside(i, j, k);
  180. }
  181. }
  182. }
  183. printf("%d ICE_BLOCK(S) INSIDE THE HOUSE NEED TO BE REMOVED\n", Inside_Block_Num);
  184. printf("%d ICE_BLOCK(S) OUTSIDE THE HOUSE NEED TO BE REMOVED\n", Outside_Block_Num);
  185. }
  186.  
  187. inline bool is_a_part_of_house(int x, int y, int z) {return !inside(x, y, z) && !outside(x, y, z);}
  188.  
  189. void remove_rest_of_block() { //把多余的方块移除
  190. for (int i = 0; i < n; i++) {
  191. for (int j = 0; j < n; j++) {
  192. for (int k = 0; k < HM; k++) if (!is_a_part_of_house(i, j, k)) remove_ice_block(i, j, k, false);
  193. }
  194. }
  195. }
  196.  
  197. int Door_X, Door_Y, Door_Max_Value = -1;
  198.  
  199. int mid(int x, int y) { //判断门是否在墙的中间
  200. if (x == HR || x == HR + HX - 1) {
  201. if (HY & 1) return y == HC + (HY >> 1);
  202. else return (y == HC + (HY >> 1)) || (y == HC + (HY - 1 >> 1));
  203. }
  204. if (y == HC || y == HC + HY - 1) {
  205. if (HX & 1) return x == HR + (HX >> 1);
  206. else return (x == HR + (HX >> 1)) || (x == HR + (HX - 1 >> 1));
  207. }
  208. //出错
  209. exit(20040826);
  210. return -1;
  211. }
  212.  
  213. int get_block_num(int x, int y) { //求出(x,y)从地面开始的两格有几个方块
  214. return Block[x][y][0] + Block[x][y][1];
  215. }
  216.  
  217. int need_block_num(int x, int y) { //求出(x,y)从地面开始的两格还需要几个方块
  218. return !Block[x][y][0] + !Block[x][y][1];
  219. }
  220.  
  221. int beside_corner(int x, int y) { //如果门在墙角旁边,就要多放方块修墙角(即可以看见),求出原有几个方块
  222. int res = 0;
  223. bool Is_Beside_Corner = false;
  224. if (x - 1 == HR) res += get_block_num(x - 1, y), Is_Beside_Corner = true;
  225. if (x + 1 == HR + HX - 1) res += get_block_num(x + 1, y), Is_Beside_Corner = true;
  226. if (y - 1 == HC) res += get_block_num(x, y - 1), Is_Beside_Corner = true;
  227. if (y + 1 == HC + HY - 1) res += get_block_num(x, y + 1), Is_Beside_Corner = true;
  228. if (!Is_Beside_Corner) res = 4;
  229. return res;
  230. }
  231.  
  232. int door_value(int x, int y) { //求出在此建门的优先级
  233. //BBmccc
  234. return need_block_num(x, y) << 4 | mid(x, y) << 3 | beside_corner(x, y);
  235. }
  236.  
  237. void get_max(int x, int y) { //更新门的位置
  238. int Value = door_value(x, y);
  239. if (Value > Door_Max_Value) Door_X = x, Door_Y = y, Door_Max_Value = Value;
  240. }
  241.  
  242. void find_door() { //找到建门的最好地点
  243. for (int i = HR + 1; i < HR + HX - 1; i++) {
  244. get_max(i, HC);
  245. get_max(i, HC + HY - 1);
  246. }
  247. for (int i = HC + 1; i < HC + HY - 1; i++) {
  248. get_max(HR, i);
  249. get_max(HR + HX - 1, i);
  250. }
  251. }
  252.  
  253. #define fix(x, y, z) cnt += !Block[x][y][z], Block[x][y][z] = true
  254. #define fix_double(x, y) cnt += need_block_num(x, y), Block[x][y][0] = Block[x][y][1] = true
  255.  
  256. bool is_door(int x, int y, int z) { //判断这个位置是否是门
  257. return x == Door_X && y == Door_Y && z < 2;
  258. }
  259.  
  260. int fix_wall() { //修墙,并求出需要的方块数
  261. int cnt = 0;
  262. for (int i = HR + 1; i < HR + HX - 1; i++) {
  263. for (int j = 0; j < Height; j++) {
  264. if (!is_door(i, HC, j)) fix(i, HC, j);
  265. if (!is_door(i, HC + HY - 1, j)) fix(i, HC + HY - 1, j);
  266. }
  267. }
  268. for (int i = HC + 1; i < HC + HY - 1; i++) {
  269. for (int j = 0; j < Height; j++) {
  270. if (!is_door(HR, i, j)) fix(HR, i, j);
  271. if (!is_door(HR + HX - 1, i, j)) fix(HR + HX - 1, i, j);
  272. }
  273. }
  274. if (Door_X - 1 == HR) fix_double(Door_X - 1, Door_Y);
  275. if (Door_X + 1 == HR + HX - 1) fix_double(Door_X + 1, Door_Y);
  276. if (Door_Y - 1 == HC) fix_double(Door_X, Door_Y - 1);
  277. if (Door_Y + 1 == HC + HY - 1) fix_double(Door_X, Door_Y + 1);
  278. return cnt;
  279. }
  280.  
  281. int fix_corner() { //修墙角,并求出需要的方块数
  282. int cnt = 0;
  283. for (int i = 0; i < Height; i++) {
  284. fix(HR, HC, i);
  285. fix(HR, HC + HY - 1, i);
  286. fix(HR + HX - 1, HC, i);
  287. fix(HR + HX - 1, HC + HY - 1, i);
  288. }
  289. return cnt;
  290. }
  291.  
  292. void make_roof() { //造屋顶
  293. Height = get_roof_height();
  294. int Make_Roof_Need = HX * HY - calc_block_num(HR, HC, HR + HX - 1, HC + HY - 1, Height);
  295.  
  296. if (Ice_Block_Num < Make_Roof_Need) PutRe("SORRY CIRNO,NOT ENOUGH ICE_BLOCK(S) TO MAKE ROOF")
  297. if (Height < 2 || HX <= 2 || HY <= 2) PutRe("SORRY CIRNO,HOUSE IS TOO SMALL");
  298.  
  299. Ice_Block_Num -= Make_Roof_Need;
  300. for (int i = HR; i < HR + HX; i++) {
  301. for (int j = HC; j < HC + HY; j++) Block[i][j][Height] = true;
  302. }
  303.  
  304. calc_rest_of_block_num();
  305. remove_rest_of_block();
  306. if (!Block[HR][HC][Height]) PutRe("SORRY CIRNO,HOUSE IS BROKEN WHEN REMOVING BLOCKS")
  307.  
  308. find_door();
  309.  
  310. int Fix_Wall_Need = fix_wall();
  311. if (Ice_Block_Num < Fix_Wall_Need) PutRe("SORRY CIRNO,NOT ENOUGH ICE_BLOCKS TO FIX THE WALL")
  312. Ice_Block_Num -= Fix_Wall_Need;
  313. puts("GOOD JOB CIRNO,SUCCESSFULLY BUILT THE HOUSE");
  314.  
  315. if (Door_Max_Value >> 4 == 2) puts("DOOR IS OK");
  316. else {
  317. puts("HOUSE HAS NO DOOR");
  318. Ice_Block_Num += Block[Door_X][Door_Y][0] + Block[Door_X][Door_Y][1];
  319. Block[Door_X][Door_Y][0] = Block[Door_X][Door_Y][1] = false;
  320. }
  321.  
  322. if (!Fix_Wall_Need) puts("WALL IS OK");
  323. else puts("WALL NEED TO BE FIXED");
  324.  
  325. int Fix_Corner_Need = fix_corner();
  326. if (Ice_Block_Num < Fix_Corner_Need) Ice_Block_Num = 0;
  327. else Ice_Block_Num -= Fix_Corner_Need;
  328. if (!Fix_Corner_Need) puts("CORNER IS OK");
  329. else puts("CORNER NEED TO BE FIXED");
  330.  
  331. printf("CIRNO FINALLY HAS %d ICE_BLOCK(S)\n", Ice_Block_Num);
  332.  
  333. if (!Inside_Block_Num && !Outside_Block_Num
  334. && !Fix_Wall_Need && !Fix_Corner_Need
  335. && (Door_Max_Value & 1 << 3) && (Door_Max_Value >> 4 == 2))
  336. puts("CIRNO IS PERFECT!");
  337.  
  338. }
  339.  
  340. void start() {
  341. scanf("%d", &n);
  342. scanf("%d", &HM);
  343. scanf("%d%d%d%d", &HR, &HC, &HX, &HY);
  344. scanf("%d", &m);
  345.  
  346. char op[20];
  347. for (Tim = 1; Tim <= m; Tim++) {
  348. scanf("%s", op);
  349. if (strcmp(op, "ICE_BARRAGE") == 0) {
  350. int R, C, D, S;
  351. scanf("%d%d%d%d", &R, &C, &D, &S);
  352. ice_barrage(R, C, D, S);
  353. continue;
  354. }
  355. if (strcmp(op, "MAKE_ICE_BLOCK") == 0) {
  356. make_ice_block();
  357. continue;
  358. }
  359. if (strcmp(op, "PUT_ICE_BLOCK") == 0) {
  360. int R, C, H;
  361. scanf("%d%d%d", &R, &C, &H);
  362. put_ice_block(R, C, H);
  363. continue;
  364. }
  365. if (strcmp(op, "REMOVE_ICE_BLOCK") == 0) {
  366. int R, C, H;
  367. scanf("%d%d%d", &R, &C, &H);
  368. remove_ice_block(R, C, H);
  369. }
  370. if (strcmp(op, "MAKE_ROOF") == 0) {
  371. make_roof();
  372. }
  373. }
  374. }
  375. }
  376. int main() {
  377. snow_house::start();
  378. return 0;
  379. }

  

[洛谷P3693]琪露诺的冰雪小屋的更多相关文章

  1. 题解 P3693 【琪露诺的冰雪小屋】

    知识点: 模拟 , 信仰 原题面 大 型 车 万 众 自 裁 现 场 分析题意: 操作: ICE_BARRAGE R C D S R:行 , C:列, D:方向 , S:强度 在(R,C) 向 D 射 ...

  2. 洛谷P1725 琪露诺

    传送门啦 本人第一个单调队列优化 $ dp $,不鼓励鼓励? 琪露诺这个题,$ dp $ 还是挺好想的对不,但是暴力 $ dp $ 的话会 $ TLE $ ,所以我们考虑用单调队列优化. 原题中说她只 ...

  3. 洛谷—— P1725 琪露诺

    https://www.luogu.org/problem/show?pid=1725 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精.某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这 ...

  4. 洛谷P1725琪露诺(单调队列优化dp)

    P1725 琪露诺 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精.某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸.于是琪 ...

  5. 洛谷 P1725 琪露诺 题解

    P1725 琪露诺 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精. 某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸.于是 ...

  6. 洛谷P1725 琪露诺 (单调队列/堆优化DP)

    显然的DP题..... 对于位置i,它由i-r~i-l的位置转移过来,容易得到方程 dp[i]=dp[i]+max(dp[i−r],...,dp[i−l]). 第一种:n2的暴力,只能拿部分分. 1 ...

  7. 【洛谷】【动态规划+单调队列】P1725 琪露诺

    [题目描述:] 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精. 某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸.于是琪露诺决定到河 ...

  8. AC日记——琪露诺 洛谷 P1725

    琪露诺 思路: 单调队列+dp: 然而劳资不会单调队列,所以,线段树水过; 来,上代码: #include <cstdio> #include <cstring> #inclu ...

  9. CODEVS 3943 数学奇才琪露诺

    [题目描述 Description] 作为上白泽慧音老师的出色弟子,数学奇才琪露诺在算术方面有很深的造诣.今天,codevs有幸请到了这位数学界的奇葩作为本场考试的第一题主考官. 琪露诺喜欢0-9之间 ...

随机推荐

  1. java简单web爬虫(网页图片)

    java简单web爬虫(网页图片)效果,执行main()方法后图片就下载道C盘的res文件夹中.没有的话创建一个文件夹代码里的常量根据自己的需求修改,代码附到下面. package com.sinit ...

  2. redis之哨兵(Sentinel)

    Redis-Sentinel是redis官方推荐的高可用性解决方案,当用redis作master-slave的高可用时,如果master本身宕机,redis本身或者客户端都没有实现主从切换的功能. 而 ...

  3. 处理laravel表单提交默认将空值转为null的问题

    比如表单提交,如果我们提交了这个字段,但是这个字段为空字符串.在Laravel中会自动转义成Null. 处理这个问题,直到找到中间件\vendor\laravel\framework\src\Illu ...

  4. Hive(2)-Hive的安装,使用Mysql替换derby,以及一丢丢基本的HQL

    一. Hive下载 1. Hive官网地址 http://hive.apache.org/ 2. 文档查看地址 https://cwiki.apache.org/confluence/display/ ...

  5. scala成长之路(7)函数进阶——可能是史上最浅显易懂的闭包教程

    由于scala中函数内部能定义函数,且函数能作为函数的返回值,那么问题来了,当返回的函数使用了外层函数的局部变量时,会发生什么呢?没错,就产生是闭包. 关于闭包的解释网上一大堆,但基本上都是照葫芦画瓢 ...

  6. python 函数 练习

    # 2.写函数,接收n个数字,求这些参数数字的和. def sum_func(*args): total = 0 for i in args: total += i return total prin ...

  7. JavaScript实现判断图片是否加载完成的3种方法整理

    JavaScript实现判断图片是否加载完成的3种方法整理 有时候我们在前端开发工作中为了获取图片的信息,需要在图片加载完成后才可以正确的获取到图片的大小尺寸,并且执行相应的回调函数使图片产生某种显示 ...

  8. Java——英文字母---18.10.11

    package lianxi;import java.io.*;import java.util.Scanner;public class file{  public static void main ...

  9. [Hbase]hbase命令行基本操作

    -进入hbase shell hbase shell - 帮助help help - 查看hbase versionversion - 查看hbase 状态 status - 创建表create 't ...

  10. Django调试models输出的SQL语句

    django1.3在shell下,调试models变得更为简单了,不用像之前的版本,手工去调用django query,才能打印出之前的代码是执行的什么SQL语句. 1.3开始只需在settings. ...