p { text-indent: 25px }
h2 { color: rgba(238, 62, 128, 1); font-family: “楷体” }
#question1 { background-color: rgba(102, 102, 102, 1); color: rgba(204, 204, 204, 1) }
#uquestion1 { background-color: rgba(102, 102, 102, 1); color: rgba(204, 204, 204, 1) }

  • 2017-3-15补充了第三题的题解
  • 2017-3-18修正了第二题AC代码的一个致命错误
  • 2017-3-18更新了页面排版
  • 2017-3-24更新了更新日志 的排版

首先来看题目:

为了准备一个独特的颁奖典礼,组织者在会场的一片 矩形区域(可看做 是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n 张地毯,编 号从1 到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后 铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。地毯铺设完成后,组 织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地 毯边界和四个顶点上的点也算被地毯覆盖。

输入描述 Input Description
输入共 n+2 行。
第一行,一个整数 n,表示总共有n 张地毯。
接下来的 n 行中,第i+1 行表示编号i 的地毯的信息,包含四个正整数
a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下
角的坐标(a,b)以及地毯在x轴和y 轴方向的长度。
第 n+2 行包含两个正整数x 和y,表示所求的地面的点的坐标(x,y)。

输出描述 Output Description
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖
则输出-1。

样例输入 Sample Input
样例1:
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2

样例2:
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5

样例输出 Sample Output
样例1:
3

样例2:
-1

数据范围及提示 Data Size & Hint
数据范围
对于 30%的数据,有n≤2;
对于 50%的数据,0≤a, b, g, k≤100;
对于 100%的数据,有0≤n≤10,000,0≤a, b, g, k≤100,000。

一道很水的题,刚开始的时候想模拟地毯的铺放来解决,RE掉四个点,后来
发现根本不需要这么做,直接判断就好了,这里两种代码都附上。

  1. //这是模拟的代码,因为用了二维数组,空间开不了多大,会提示“too large”
  2. //开小了又会RE,这里只是用来辅助大家理解题意。
  3. #include <cstdio>
  4. #include <iostream>
  5. using namespace std;
  6. int n, a, b, g, k, x, y;
  7. int map[7010][7010];
  8. template<class T>inline void read(T &res)
  9. {
  10. static char ch;
  11. while( (ch=getchar()) < \'0\' || ch > \'9\');
  12. res = ch - 48;
  13. while( (ch = getchar() ) >= \'0\' && ch <= \'9\')
  14. res = ch - 48 + res * 10;
  15. }
  16. int main()
  17. {
  18. freopen("carpet.in", "r", stdin);
  19. freopen("carpet.out", "w", stdout);
  20. read(n);
  21. for (int i = 1; i <= n; i++)
  22. {
  23. read(a);read(b);read(g);read(k);
  24. for (int l = b; l <= b+k; l++)
  25. for (int j = a; j <= a+g; j++)
  26. map[l][j] = i;
  27. }
  28. read(x); read(y);
  29. if (map[y][x] != 0) cout << map[y][x];
  30. else cout << -1;
  31. return 0;
  32. }
  1. //第二种直接判断的代码,时空复杂度都相当优。
  2. #include <stdio.h>
  3. #include <iostream>
  4. #include <stdlib.h>
  5. using namespace std;
  6. int i, j, k, n, x, y;
  7. int ans[10005][5] = {0};
  8. template<class T>inline void read(T &res)
  9. {
  10. static char ch;
  11. while( (ch=getchar()) < \'0\' || ch > \'9\');
  12. res = ch - 48;
  13. while( (ch = getchar() ) >= \'0\' && ch <= \'9\')
  14. res = ch - 48 + res * 10;
  15. }
  16. int main()
  17. {
  18. read(n);
  19. for(i = 1; i <= n; i++)
  20. for(j = 1; j <= 4; j++)
  21. read(ans[i][j]);
  22. read(x);read(y);
  23. for(i = n; i >= 1; i--)
  24. if( ( (ans[i][1] + ans[i][3] ) >= x) && ( (ans[i][2] + ans[i][4] ) >= y ) && ans[i][1] <= x && ans[i][2] <= y )
  25. {
  26. cout << i;
  27. return 0;
  28. }
  29. cout << -1;
  30. return 0;
  31. }

 以下是评测截图。

依旧是先上题目

丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从1 到n编号。 每家客栈都按照某一种色调进行装饰(总共k 种,用整数0~k-1表示) 且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。     两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈 因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店 喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈)且 咖啡店的最低消费不超过p。     他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费 不超过p元的咖啡店小聚。

输入描述 Input Description
     共n+1 行。
     第一行三个整数 n,k,p,每两个整数之间用一个空格隔开,分别表示客栈
的个数,色调的数目和能接受的最低消费的最高值;接下来的 n 行,第i+1
行两个整数,之间用一个空格隔开,分别表示i 号客栈的装饰色调和i 号客
栈的咖啡店的最低消费

输出描述 Output Description
     输出只有一行,一个整数,表示可选的住宿方案的总数。

样例输入 Sample Input
5 2 3
0 5
1 3
0 2
1 4
1 5

样例输出 Sample Output
3

数据范围
对于 30%的数据,有n≤100;
对于 50%的数据,有n≤1,000;
对于 100%的数据,有2≤n≤200,000,0<k≤50,0≤p≤100, 0≤最低消费≤100。

先分析题目,很明显可以暴力(手动滑稽),暴力的思路就是直接枚举,从第一家客栈开始找,找到颜色相符合的就去枚举价格,如果价格符合要求(≤p)就ans++,不过很明显,会T掉。

  1. #include <cstdio>
  2. #include <iostream>
  3. using namespace std;
  4. int n, k, p, ans;
  5. int t = 1;
  6. int color[200010];
  7. int house[200010];
  8. template<class T>inline void read(T &res)
  9. {
  10. static char ch;
  11. while( (ch=getchar()) < \'0\' || ch > \'9\');
  12. res = ch - 48;
  13. while( (ch = getchar() ) >= \'0\' && ch <= \'9\')
  14. res = ch - 48 + res * 10;
  15. }
  16. int DFS()
  17. {
  18. int mi;
  19. for (register int i = 1; i <= n; i++)
  20. {
  21. for (register int j = t+1; j <= n; j++)
  22. {
  23. if (color[j] == color[t])
  24. {
  25. mi = 233333333;
  26. for (int e = t; e <= j; e++)
  27. {
  28. if (house[e] < mi)
  29. {
  30. mi = house[e];
  31. }
  32. }
  33. if (mi <= p) ans++;
  34. }
  35. }
  36. t++;
  37. }
  38. return ans;
  39. }
  40. int main()
  41. {
  42. read(n);read(k);read(p);
  43. for (register int i = 1; i <= n; i++)
  44. {
  45. read(color[i]);
  46. read(house[i]);
  47. }
  48. cout << DFS();
  49. return 0;
  50. }

可以很清晰的看见这个做法有多么简单粗暴,但是就算是加了register一样会超时,超四个点,那么正解是什么呢?

如果一家编号为i咖啡店的最低消费大于p,则记flag[i]=1否则,flag[i]=0但计算满足要求的对数有点恼火,从反面思考:从1到n扫描出flag值等于1的连续客栈(在此区间内找到的客栈均为不满足要求的方案),在检测时用cnt[j]记录当前颜色为j的客栈出现次数cnt[j]++;count+=(cnt [j]-1); (新的客栈可以与当前任意颜色相同客栈组合)可以数出颜色相同但不满足要求的客栈对数。答案ans=sum-count.(sum为所有颜色相同的客栈对数)即为满足要求的客栈对数。

直接贴代码。

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <algorithm>
  4. using namespace std;
  5. int Count, sum, n, k, p, tmp;
  6. int cnt[100];
  7. int col[200010];
  8. bool flag[200010];
  9. int main()
  10. {
  11. scanf("%d%d%d", &n, &k, &p);
  12. for(int i = 1; i <= n; i++)
  13. {
  14. scanf("%d", &col[i]);
  15. scanf("%d", &tmp);
  16. if(tmp > p) flag[i] = 1;
  17. }
  18. for(int i = 1; i <= n; i++)
  19. {
  20. if(flag[i] == 0)
  21. {
  22. memset(cnt, 0, sizeof(cnt));
  23. continue;
  24. }
  25. cnt[col[i]]++;
  26. Count += (cnt[col[i]] - 1);
  27. }
  28. memset(cnt, 0, sizeof(cnt));
  29. for(int i = 1; i <= n; i++)
  30. {
  31. cnt[col[i]]++;
  32. sum += (cnt[col[i]] - 1);
  33. }
  34. cout << sum-Count;
  35. return 0;
  36. }

Mayan puzzle 是最近流行起来的一个游戏。 游戏界面是一个7 行5 列的棋盘,上面堆放 着一些方块,方 块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块 之上。游 戏通关是指在规定的步数内消除所有的方块,消除方块 的规则如下:

1、每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块
一格:当拖动这一方 块时,如果拖动后到达的位置(以下称目标
位置)也有方块,那么这两个方块将交换位置(参 见输入输出样
例说明中的图6 到图7);如果目标位置上没有方块,那么被拖动
的方块将从 原来的竖列中抽出,并从目标位置上掉落

2、任一时刻,如果在一横行或者竖列上有连续三个或者三个以上
相同颜色的方块,则 它们将立即被消除(参见图1 到图3)。注意:
a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(
例如下面图4,三个颜 色为1 的方块和三个颜色为2 的方块会同
时被消除,最后剩下一个颜色为2 的方块)。
b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列
上满足消除条件的所 有方块会被同时消除(例如下面图5 所示的
情形,5 个方块会同时被消除)。

3、方块消除之后,消除位置之上的方块将掉落,掉落后可能会引
起新的方块消除。注 意:掉落的过程中将不会有方块的消除。 上
面图 1 到图3 给出了在棋盘上移动一块方块之后棋盘的变化。棋
盘的左下角方块的坐 标为(0, 0),将位于(3, 3)的方块向左
移动之后,游戏界面从图1 变成图2 所示的状态, 此时在一竖列上
有连续三块颜色为4 的方块,满足消除条件,消除连续3 块颜色为4
的方块 后,上方的颜色为3 的方块掉落,形成图3 所示的局面。

【输入描述】
输入共六行。
第一行输入一个正整数n,表示要求游戏通关的步数;
接下来五行,描述了7*5的游戏界面,每行输入若干个整数,每行以一
个0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于10种,从
1开始顺序编号,相同数字表示相同颜色)。
保证初始棋盘中没有可以消除的方块。

【输出描述】
如果有解决方案,输出n行,每行包含三个整数x、y、g,表示一次移
动,其中(x,y)表示要移动的方块的坐标,g表示移动的方向,1表示
向右移动,-1表示向左移动。当存在多组解时,按照x为第一关健字,
y为第二关健字,1优先于-1,输出一组字典序最小的解。游戏界面左
下角的坐标为(0,0);

如果没有解决方案,输出一个整数-1。

【输入样例】
3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0

【输出样例】
2 1 1
3 1 1
3 0 1

 据坊间传闻这是NOIP历年来最难得一道搜索,对个人而言确实还是有难度。

其实主要难在删除块儿和下落,还有具体的优化,下面上代码,代码上都有批注。

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. int n;
  7. int Num[15], i[6][8], Ans[6][3];
  8. bool DEL(int i[6][8]) //清除
  9. {
  10. bool Flag = 0, f[6][8]={0};
  11. for (int a = 1; a <= 5; a++)
  12. for (int b = 1; b <= 7; b++)
  13. if (i[a][b])
  14. {
  15. if (a <= 3 && i[a][b] == i[a+1][b] && i[a+1][b] == i[a+2][b])
  16. f[a][b] = f[a+1][b] = f[a+2][b] = true;
  17. if (b <= 5 && i[a][b] == i[a][b+1] && i[a][b+1] == i[a][b+2])
  18. f[a][b] = f[a][b+1] = f[a][b+2] = true;
  19. }
  20. for (int a = 1; a <= 5; a++)
  21. for (int b = 1; b <= 7; b++)
  22. if (f[a][b])
  23. {
  24. i[a][b] = 0;
  25. Flag = true;
  26. }
  27. return Flag;
  28. }
  29. void Falldown(int i[6][8]) //下落
  30. {
  31. for (int a = 1; a <= 5; a++) //填补
  32. {
  33. int t = 0;
  34. for (int b = 1; b <= 7; b++)
  35. {
  36. int T = i[a][b];
  37. i[a][b] = 0;
  38. if (T)
  39. i[a][++t] = T;
  40. }
  41. }
  42. }
  43. bool Check(int i[6][8]) //检验
  44. {
  45. for (int a = 1; a <= 5; a++)
  46. for (int b = 1; b <= 7; b++)
  47. if (i[a][b])
  48. return false;
  49. return true;
  50. }
  51. void DFS(int T, int i[6][8]) //DFS
  52. {
  53. if (T > n) //超步子
  54. {
  55. if (Check(i))
  56. {
  57. for (int a = 1; a <= n; a++)
  58. if (Ans[a][2]) //判断左右
  59. printf("%d %d -1\n", Ans[a][0], Ans[a][1]-1);
  60. else
  61. printf("%d %d 1\n", Ans[a][0]-1, Ans[a][1]-1);
  62. exit(0);//结束
  63. }
  64. return;
  65. }
  66. memset(Num, 0, sizeof(Num)); //存储某种颜色格子现存数
  67. for (int a = 1; a <= 5; a++)
  68. for (int b = 1; b <= 7; b++)
  69. if (i[a][b])
  70. Num[i[a][b]]++;
  71. for (int a = 1; a <= 10; a++)
  72. if (Num[a] == 1 || Num[a] == 2) //等于0时并不需要返回
  73. return;
  74. int f[6][8] = {0}; //临时数组
  75. for (int a = 1; a < 5; a++)
  76. for (int b = 1; b <= 7; b++)
  77. if (i[a][b] != i[a+1][b]) //颜色不一样才交换
  78. {
  79. memcpy(f, i, sizeof(f));//复制值
  80. Ans[T][0] = a;
  81. Ans[T][1] = b;
  82. Ans[T][2] =! i[a][b]; //若空,即是true,若有,即是false
  83. swap(f[a][b], f[a+1][b]); //交换
  84. Falldown(f);
  85. while (DEL(f)) //消除
  86. Falldown(f);
  87. DFS(T+1, f);
  88. }
  89. }
  90. int main()
  91. {
  92. scanf("%d", &n);
  93. for (int a = 1; a <= 5; a++)
  94. for (int b = 1; ; b++)
  95. {
  96. scanf("%d", &i[a][b]); //i列j行
  97. if (!i[a][b]) //存储颜色
  98. break;
  99. }
  100. DFS(1, i);
  101. printf("-1");//执行至此如果没有结束则输出-1
  102. return 0;
  103. }

版权声明:本文为GuanHuaEdison原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/GuanHuaEdison/p/6535478.html