考场想了 5.5 h,第一部分分死活打不出来,做到崩盘,现在重做,感觉自己就是一个sb,放学在地铁上一眼就会了。哎。

可以把一个要求看作一个长度为 \(m\) 的区间:\([l, l + m - 1]\),可以要求这段条件的充要条件是找到一种循环移位,每个墙恰好可以被那个工人挖。然后问题是用最少的区间覆盖完 \([0, n - 1]\)。

可以设一个 DP:

$f_i $:刷完前 \(i\) 个墙的最小要求次数。

  • 如果 \([i - m + 1, i]\) 可以刷,那么 \(f_i = \min_{i-m\le j <i}(f_j) + 1\)。
  • 否则 \(f_i\) 是正无穷。

这个东西显然是一个滑动窗口最值,用单调队列优化,我们现在的就要求快速判断 \([i - m + 1, i]\) 能不能刷。

设 \(len_{i, j}\) 为第 \(i\) 个墙,第 \(j\) 个人刷,最多可以循环移位向前延伸多少个。

对于一个 \(i\),枚举 \(C_i\) 颜色对应的所有的工人 \(u\),转移 \(len_{i, u} = len_{i - 1, (u - 1) \bmod m} + 1\)。

由于 \(\sum f(k)^2 \le 400000\),所以 \(f(k)\) 是 \(600\) 量级的,时间复杂度是 \(O(n \max(f(k)))\) 是可以过的。

但是空间不够,滚动数组就好了,但是还要保证转移的是 \(i - 1\) 次,所以每次转移赋值 \(g_{i \bmod 2, j} = i\),表示这个循环移位最后的位置是 \(i\)。转移判断上次的是不是 \(i - 1\) 就行了。

单调队列还有一些细节,比如正无穷不能扔进队列之类。

#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100005, M = 50005, INF = 0x3f3f3f3f; int f[N], q[N], g[2][M], len[2][M]; vector<int> d[N]; int minimumInstructions(
int n, int m, int K, std::vector<int> c,
std::vector<int> a, std::vector<std::vector<int> > b) {
memset(f, 0x3f, sizeof f);
memset(g, -1, sizeof g);
for (int i = 0; i < K; i++) d[i].clear();
for (int i = 0; i < m; i++) {
for (int j = 0; j < a[i]; j++) {
d[b[i][j]].push_back(i);
}
}
int hh = 0, tt = -1;
for (int i = 0; i < n; i++) {
bool ok = false;
for (int j = 0; j < d[c[i]].size(); j++) {
int u = d[c[i]][j];
g[i & 1][u] = i, len[i & 1][u] = 1;
if (i && g[(i - 1) & 1][(u + m - 1) % m] == i - 1) len[i & 1][u] += len[(i - 1) & 1][(u + m - 1) % m];
if (len[i & 1][u] >= m) ok = true;
}
if (ok) {
while (hh <= tt && q[hh] < i - m) hh++;
if (i < m) f[i] = 1;
else if (hh <= tt) f[i] = f[q[hh]] + 1;
if (f[i] != INF) {
while (hh <= tt && f[q[tt]] >= f[i]) tt--;
q[++tt] = i;
}
}
}
return f[n - 1] == INF ? -1 : f[n - 1];
}

最新文章

  1. ansible 初探nginx安装
  2. WPF知识总结(一)
  3. ubuntu10.04下修改mysql的datadir的问题
  4. ecshop商品-》获取促销商品
  5. IOS第14天(2, Modal控制)
  6. Xenia and Divisors
  7. QT 多线程程序设计
  8. javaweb学习总结(四十一)——Apache的DBUtils框架学习
  9. UVA 11796 Dog Distance(向量)
  10. js方法在iframe父子窗口
  11. PH日期格式化
  12. 找回停掉docker的文件
  13. pyhton 爬虫爬去吾爱精品软件的信息并写入excel
  14. Vue-Router路由Vue-CLI脚手架和模块化开发 之 使用props替代路由对象的方式获取参数
  15. 深入C++的new
  16. 使用Iperf工具测试android系统网络wifi的吞吐量wifithrougput
  17. R语言NULL、NA、0
  18. Linux下安装python-2.7 先zlib
  19. SQL Server 2008过期导致MSSQLSERVER服务无法启动现象
  20. AtomicIntegerFieldUpdater用法

热门文章

  1. PF_PACKET&amp;&amp;tcpdump
  2. 守护进程详解以及start-stop-daemon命令
  3. Django 配置 Mysql
  4. Python_用PyQt5 建 notepad 界面
  5. CSS 常用列表样式
  6. ERP应收应付进阶操作与子流程--开源软件诞生29
  7. 深度分析:java设计模式中的原型模式,看完就没有说不懂的
  8. 如何在Mac上安全彻底的卸载软件?
  9. 如何使用系统清理缓存软件优化MacBook
  10. Java中的主线程