参考题解

\(\text{Solution}\)

我们发现5个行为中2操作与其它操作无关,所以我们采用贪心,尽量让多的时间去攻击大佬。

设 \(f[i][j]\) 表示前 \(i\) 天剩 \(j\) 血量所能攻击的最多次数,是个很简单的 \(dp\) ,决策就是刷不刷水题, ​\(D​\) 就是最多的时间。

  1. void DP() {
  2. memset(f, -1, sizeof f);
  3. f[0][MC] = 0;
  4. for (int i = 0; i < n; ++ i)
  5. for (int j = 0; j <= MC; ++ j) {
  6. if (f[i][j] == -1) continue;
  7. chkmax(D, f[i][j]);
  8. int t = j - a[i + 1];
  9. if (t < 0) continue;
  10. chkmax(f[i + 1][t], f[i][j] + 1);
  11. t = min(t + w[i + 1], MC);
  12. chkmax(f[i + 1][t], f[i][j]);
  13. }
  14. }

那么现在就是给你很多组询问,询问是否能在 \(D\) 天内击败大佬。

考虑一个二元组 \((x, y)\) 表示达到讽刺值为 \(x\) ,能力值为 \(y\) 的最少天数。

然后这些二元组我们可以从 \((1,0)\) \(bfs\)暴力求。

  1. void Get() {
  2. queue<pii> Q;
  3. Q.push(pii(1, 0));
  4. M[pii(1, 0)] = 0;
  5. while (Q.size()) {
  6. pii x = Q.front(); Q.pop();
  7. int now = M[x];
  8. if (vis[x.first])
  9. chkmin(V[x.first], now + 1);
  10. else {//V[x]: 至少到V[x]天讽刺值为x,并且明天可以继续累积
  11. vis[x.first] = 1;
  12. b[++tot] = x.first;
  13. V[x.first] = now + 1;
  14. }
  15. if (now >= D - 1) continue;//明天不能继续累积,只能攻击
  16. if (!M.count(pii(x.first, x.second + 1))) {//升级
  17. M[pii(x.first, x.second + 1)] = now + 1;
  18. Q.push(pii(x.first, x.second + 1));
  19. }
  20. if (x.second > 1 && 1ll * x.first * x.second < maxM &&
  21. !M.count(pii(x.first * x.second, x.second))) {//累积讽刺值
  22. M[pii(x.first * x.second, x.second)] = now + 1;
  23. Q.push(pii(x.first * x.second, x.second));
  24. }
  25. }
  26. }

求出二元组后,对所有二元组按讽刺值排序(第一维),记 \(g[i]\) 为第 \(i\) 个二元组 \(x_i-y_i\) 的值。

考虑不怼大佬,回嘴击败大佬:

  1. if (C < D) return true;

考虑怼一次大佬,需满足有 \(x_i\le C​\) \(\text{and}​\) \(C\le x_i +(d -y_i)=g[i]+d​\)

  1. for (int i = 1; i <= tot; ++ i)
  2. if (C >= x[i] && g[i] >= C - D)
  3. return 1;//怼一次

考虑怼两次大佬,需满足有 \(x_i+x_j\le C\ \text{and}\ C\le x_i+x_j+(d-y_i-y_j)\)

两个指针扫描,由于排好序先保证 \(x_i+x_j\le C\) 然后维护前缀 \(g[i]\) 最大值 \(Mx[i]\)

  1. for (int i = 1; i <= tot; i++) {
  2. if (x[i] > c)
  3. return 0;//如果当前大于c,那么之后必然大于c,不满足条件1,是一个小剪枝
  4. while (tail && x[i] + x[tail] > C)
  5. --tail;//由于x单调,可能的答案在i到tail之间
  6. if (tail && g[i] + Mx[tail] >= C - D)
  7. return 1;
  8. }

这题难就难在将原问题抽离成两个单独的问题,将复杂的问题抽离成一些容易的,比较好处理的问题,会对结题有很大帮助,然后就是要多积累,熟悉经典问题的解法,如本题的讨论怼几次的问题上为了满足条件,运用了双指针扫描 \((two\_pointer)\) 的方法。

\(\text{Source}\)

  1. #include <bitset>
  2. #include <map>
  3. #include <queue>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <iostream>
  7. #include <assert.h>
  8. #include <algorithm>
  9. using namespace std;
  10. #define LL long long
  11. #define debug(...) fprintf(stderr, __VA_ARGS__)
  12. #define GO debug("GO\n")
  13. inline int rint() {
  14. register int x = 0, f = 1; register char c;
  15. while (!isdigit(c = getchar())) if (c == '-') f = -1;
  16. while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
  17. return x * f;
  18. }
  19. template<typename T> inline void chkmin(T &a, T b) { a > b ? a = b : 0; }
  20. template<typename T> inline void chkmax(T &a, T b) { a < b ? a = b : 0; }
  21. const int N = 105;
  22. const int maxM = 1e8 + 5;
  23. const int maxN = 1e6 + 10;
  24. #define pii pair<int, int>
  25. bitset<maxM> vis;
  26. map<pii, int> M;
  27. map<int, int> V;
  28. int n, m, MC, D, tot, a[N], w[N], b[maxN], f[N][N], g[maxN], Mx[maxN];
  29. void DP() {
  30. memset(f, -1, sizeof f);
  31. f[0][MC] = 0;
  32. for (int i = 0; i < n; ++ i)
  33. for (int j = 0; j <= MC; ++ j) {
  34. if (f[i][j] == -1) continue;
  35. chkmax(D, f[i][j]);
  36. int t = j - a[i + 1];
  37. if (t < 0) continue;
  38. chkmax(f[i + 1][t], f[i][j] + 1);
  39. t = min(t + w[i + 1], MC);
  40. chkmax(f[i + 1][t], f[i][j]);
  41. }
  42. }
  43. void Get() {
  44. queue<pii> Q;
  45. Q.push(pii(1, 0));
  46. M[pii(1, 0)] = 0;
  47. while (Q.size()) {
  48. pii x = Q.front(); Q.pop();
  49. int now = M[x];
  50. if (vis[x.first])
  51. chkmin(V[x.first], now + 1);
  52. else {
  53. vis[x.first] = 1;
  54. b[++tot] = x.first;
  55. V[x.first] = now + 1;
  56. }
  57. if (now >= D - 1) continue;
  58. if (!M.count(pii(x.first, x.second + 1))) {
  59. M[pii(x.first, x.second + 1)] = now + 1;
  60. Q.push(pii(x.first, x.second + 1));
  61. }
  62. if (x.second > 1 && 1ll * x.first * x.second < maxM &&
  63. !M.count(pii(x.first * x.second, x.second))) {
  64. M[pii(x.first * x.second, x.second)] = now + 1;
  65. Q.push(pii(x.first * x.second, x.second));
  66. }
  67. }
  68. }
  69. bool solve() {
  70. int tail = tot, C;
  71. scanf("%d", &C);
  72. if (C < D) return 1;
  73. for (int i = 1; i <= tot; ++ i)
  74. if (C >= b[i] and g[i] >= C - D)
  75. return 1;
  76. for (int i = 1; i <= tot; ++ i) {
  77. if (b[i] > C) return 0;
  78. while (tail and b[i] + b[tail] > C) tail --;
  79. if (tail and g[i] + Mx[tail] >= C - D) return 1;
  80. }
  81. return 0;
  82. }
  83. int main() {
  84. #ifndef ONLINE_JUDGE
  85. freopen("xhc.in", "r", stdin);
  86. freopen("xhc.out", "w", stdout);
  87. #endif
  88. scanf("%d%d%d", &n, &m, &MC);
  89. for (int i = 1; i <= n; ++ i) scanf("%d", a + i);
  90. for (int i = 1; i <= n; ++ i) scanf("%d", w + i);
  91. DP();
  92. if (D == 0) {
  93. for (int i = 1; i <= m; ++ i) printf("0\n");
  94. return 0;
  95. }
  96. Get();
  97. sort(b + 1, b + 1 + tot);
  98. for (int i = 1; i <= tot; ++ i) {
  99. g[i] = b[i] - V[b[i]];
  100. Mx[i] = max(Mx[i - 1], g[i]);
  101. }
  102. while (m --)
  103. puts(solve() ? "1" : "0");
  104. }

[HNOI2017]大佬的更多相关文章

  1. bzoj4828 [Hnoi2017]大佬

    Description 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语.你作为一个OIER,面对这样的事情非常 ...

  2. [AH/HNOI2017]大佬

    题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...

  3. [bzoj4828][Ah/Hnoi2017]大佬

    来自FallDream的博客,未经允许,请勿转载,谢谢. 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你 ...

  4. [AH2017/HNOI2017]大佬

    题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...

  5. [AHOI2017/HNOI2017]大佬

    Description: 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事 ...

  6. BZOJ4828 AHOI/HNOI2017大佬(动态规划+bfs)

    注意到怼大佬的操作至多只能进行两次.我们逐步简化问题. 首先令f[i][j]表示第i天结束后自信值为j时至多有多少天可以进行非防御操作(即恢复自信值之外的操作).这个dp非常显然.由于最终只需要保证存 ...

  7. HNOI2017大佬

    贼难的一道题 虽然算法都不难,但组合起来就是想不到 首先,最简单的一步,对所有大佬,嘲讽你减的自信值和你做水题回复自信值都是不变的,写个\(dp\),设\(dp[i][j]\)表示第\(i\)天自信值 ...

  8. [AH2017/HNOI2017]大佬(动态规划 搜索)

    /* 神仙yyb 理解题意可以发现 能够对大佬造成的伤害只和你怼了多少天大佬有关, 而且显然天数越多越好 那么我们可以先通过预处理来找出我们最多能够怼多少天大佬 然后我们发现最后我们能怼的血量状态数是 ...

  9. 【题解】HNOI2017大佬

    哎……做了几个小时最后还是没能想到怼大佬的合法性到底怎么搞.写暴力爆搜感觉复杂度爆炸就没敢写 bfs / dfs 一类,后来发现在种种的约束条件下(远小于所给的 \(n, m\))复杂度完全是可以承受 ...

随机推荐

  1. MySQL学习之流程结构

    流程结构 流程结构:代码的执行顺序. if分支 根据要求选择合适的执行部分. 基本语法 if在MySQL中有两种基本用法 1.用在select查询当中,当作一种条件来进行判断. 基本语法:if(条件, ...

  2. 如何利用Linux去油管下载带字幕的优质英文资料提升英文听力和词汇量

    非常方便地从油管下载你需要的任何英文视频资料,并且带字幕,方便你学习某个特定领域的词汇: [step1,Centos6系统安装youtbe-dl下载带英文字幕的视频] 1.首先需要安装youtube- ...

  3. Kafka 学习翻译 - 介绍

    Kafka是一个分布式的流式平台.可以从几个方面理解: 1. 三个重要的能力: 能够实现流式的发布和订阅数据,类似于消息队列或者企业级的消息分发系统. 能够在提供一定容错性和持久性能力的基础上存储数据 ...

  4. Hexo博客部署到个人服务器

    本文跳过阿里云创建git仓库.hexo部署到github的步骤,有需要的可以移步下面博客地址查看: 在阿里云服务器上创建git远程仓库 使用Hexo建立博客 一.服务器相关配置 本文使用hexo在本地 ...

  5. AtCoder Regular Contest 098 D - Xor Sum 2 区间异或=相加 DP思想

    题意:给出n个数,求它的连续子序列中,满足下列公式,(l,r)的对数有多少对 Al xor Al+1 xor … xor Ar=Al + Al+1 + … + Ar 思路:由题意可以得到,连续子序列, ...

  6. 构建工具——maven的补充

    1.安装jar到本地仓库 有时候有部分jar由于在maven的中央仓库,只能引用本地的,可以将jar安装到本地仓库进行操作(请先确保mvn命令可以正常运行) mvn install:install-f ...

  7. linux怎么把英文版火狐浏览器改成中文

    一.按alt打开菜单栏,点击help>about firefox查看自己的火狐浏览器版本 比如我的是52.4.0版本 二打开网址 http://ftp.mozilla.org/pub/firef ...

  8. Android stado 运行项目,apk does not exist on disk.

    报错如下: 03/12 21:38:56: Launching iReader The APK file F:\git\iReader_nubia\iReader\build\outputs\apk\ ...

  9. Altium designer18设置原理图尺寸

    1. AD18版本设置原理图尺寸和以前版本不一样,具体是在界面右侧Properties里面的Sheet Sizes.

  10. MongoDB 安装 增删改查

    MongoDB   一 介绍 1.高性能的数据存储解决方案是大多数大型Web应用程序和服务的核心.后端数据库负责存储一切东西,从用户账户的信息到购物车中的商品,以及博客和评论数据等.好的Web应用需要 ...