zoukankan      html  css  js  c++  java
  • APIO2020 粉刷墙壁

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

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

    可以设一个 DP:

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

    • 如果 ([i - m + 1, i]) 可以刷,那么 (f_i = min_{i-mle 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) mod m} + 1)

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

    但是空间不够,滚动数组就好了,但是还要保证转移的是 (i - 1) 次,所以每次转移赋值 (g_{i mod 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];
    }
    
    
  • 相关阅读:
    web前端的发展态势
    AngularJs 简单入门
    css代码优化篇
    git提交报错:Please make sure you have the correct access rights and the repository exists.
    Activiti工作流框架学习
    遍历map集合的4种方法
    js设置日期、月份增加减少
    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    webservice_rest接口_学习笔记
    相互匹配两个list集合+动态匹配${}参数
  • 原文地址:https://www.cnblogs.com/dmoransky/p/13805097.html
Copyright © 2011-2022 走看看