思路:

本质上能进行的操作就是我们算出从第 \(i\) 块砖开始,连续刷 \(M\) 块砖,是否有承包商可以刷出期望颜色。

那么设 \(f_i\) 表示 \([i,i+m-1]\) 是否合法,那么就变成了最小区间覆盖问题。

最小区间覆盖问题

令 \(Max\) 表示当前覆盖了 \([1,Max]\)。

那么我们需要找到左端点在 \([1,Max+1]\) 内,且右端点最大的区间。

在本题中因为区间长度都为 \(m\),那么我们只需要找到尽可能在最后的合法 \(f_i\)。

此时 \(Max \gets i+m-1\),那么对于小于 \(j\) 的 \(i\),是无法覆盖到 \(i+m-1\) 之后的,于是就没有贡献了,于是我们可以直接走指针维护。

最小区间覆盖代码
ll get(){
ll Max=-1,x=0,id,ans=0;
while(Max<n-1){
id=-1;
while(x<=Max+1&&x<n){
if(f[x])
id=x;
x++;
}
if(id==-1)
return -1;
Max=id+m-1;
ans++;
}
return ans;
}

那么我们需要考虑的就是如何求出 \(f_i\)。

28pts:

对于每个 \(i\),暴力枚举一个 \(j\),然后查看是否能匹配上。

时间复杂度为 \(O(NM^2)\)。

51pts:

考虑动态规划优化,定义 \(dp_{i,j}\) 表示从第 \(i\) 块墙壁开始,从第 \(j\) 个商家开刷最多能刷几块墙。

那么若第 \(j\) 个商家不能刷第 \(i\) 个墙壁,则:

\[dp_{i,j}=0
\]

否则能刷:

\[dp_{i,j} = dp_{i+1,(j+1) \bmod M} + 1
\]

注意,空间开不下,考虑滚动数组优化。

时间复杂度为 \(O(NM)\)。

震惊的是,这玩意儿竟然过了……

离大谱。

$O(NM)$ 代码
int minimumInstructions(int N, int M, int K,vector<int> C,vector<int> A,vector<vector<int>> B){
n=N,m=M,k=K;
for(int i=0;i<n;i++)
a[i]=C[i];
for(int i=0;i<m;i++){
len[i]=A[i];
for(auto v:B[i])
s[v].push_back(i);
}
for(int i=n-1;i>=0;i--){
for(int j=0;j<m;j++)
dp[i&1ll][j]=0;
for(auto j:s[a[i]]){
dp[i&1ll][j]=dp[(i&1ll)^1ll][(j+1)%m]+1;
if(dp[i&1ll][j]>=m)
f[i]=1;
}
}
cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB"<<'\n';
return get();
}

100pts:

注意到可以优化上面状态转移的 \(j\)。

我们可以提前预处理能刷颜色 \(x\) 的承包商的集合 \(S_x\),那么 \(j \in S_{c_i}\)。

但是因为是滚动数组,实时清空的话复杂度又上去了,那么再维护一个时间戳即可。

时间复杂度为 \(O(\sum f(k))\)。

完整代码:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef int ll;
bool Begin;
const ll N=100100,M=50050;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll n,m,k;
ll a[N],len[M];
ll dp[2][M],low[2][M];
vector<ll> s[N];
bool f[N];
bool End;
ll get(){
ll Max=-1,x=0,id,ans=0;
while(Max<n-1){
id=-1;
while(x<=Max+1&&x<n){
if(f[x])
id=x;
x++;
}
if(id==-1)
return -1;
Max=id+m-1;
ans++;
}
return ans;
}
int minimumInstructions(int N, int M, int K,vector<int> C,vector<int> A,vector<vector<int>> B){
n=N,m=M,k=K;
for(int i=0;i<n;i++)
a[i]=C[i];
for(int i=0;i<m;i++){
len[i]=A[i];
for(auto v:B[i])
s[v].push_back(i);
}
for(int i=n-1;i>=0;i--){
for(auto j:s[a[i]]){
if(low[(i&1ll)^1ll][(j+1)%m]!=i+1)
dp[i&1ll][j]=1;
else
dp[i&1ll][j]=dp[(i&1ll)^1ll][(j+1)%m]+1;
low[i&1ll][j]=i;
if(dp[i&1ll][j]>=m)
f[i]=1;
}
}
cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB"<<'\n';
return get();
}

P6764 [APIO2020] 粉刷墙壁的更多相关文章

  1. APIO2020 粉刷墙壁

    考场想了 5.5 h,第一部分分死活打不出来,做到崩盘,现在重做,感觉自己就是一个sb,放学在地铁上一眼就会了.哎. 可以把一个要求看作一个长度为 \(m\) 的区间:\([l, l + m - 1] ...

  2. Codeforces Round #198 (Div. 2)

    A.The Wall 题意:两个人粉刷墙壁,甲从粉刷标号为x,2x,3x...的小块乙粉刷标号为y,2y,3y...的小块问在某个区间内被重复粉刷的小块的个数. 分析:求出x和y的最小公倍数,然后做一 ...

  3. [SinGuLaRiTy] NOIP互测模拟赛

    [SinGuLaRiTy-1045] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 源文件名 输入输出文件 时间限制 内存限制 淘气的cch ...

  4. 【资料总结】html开发小实例

    目 录 第1章 1 HTML的基本标签 1 第2章 25 表格基础 25 第3章 53 表单和框架 53 第4章 77 CSS样式表 77 第5章 104 使用Dreamweaver制作网页 104 ...

  5. as well as

    一.as well 用法: 1.as well常用作状语,作“又:也”解,相当于too或also,常位于句末,无须用逗号与句子分开.如: I am going to London and my sis ...

  6. 【日语】日语单词N3_N4_N5

    日语单词N3_N4_N5 单 词 讲 解 あ行单词 ああ:0[副]那样.那种 例句:ああ言うことはしないほうがいい.那样的事情最好不做. 電車の窓からごみを棄てているああ言うことはしないほうがいい. ...

  7. 日语单词N3_N4_N5

    单 词 讲 解 あ行单词 ああ:0[副]那样.那种 例句:ああ言うことはしないほうがいい.那样的事情最好不做. 電車の窓からごみを棄てているああ言うことはしないほうがいい. 挨拶(あいさつ):① 寒暄 ...

  8. java设计模式3——建造者模式

    java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...

  9. poj1821 Fence(dp,单调队列优化)

    题意: 由k(1 <= K <= 100)个工人组成的团队应油漆围墙,其中包含N(1 <= N <= 16 000)个从左到右从1到N编号的木板.每个工人i(1 <= i ...

  10. [LeetCode] Paint Fence 粉刷篱笆

    There is a fence with n posts, each post can be painted with one of the k colors. You have to paint ...

随机推荐

  1. OpenSearch 与 Elasticsearch:哪个开源搜索引擎适合您?

    当谈论到搜索引擎产品时,Elasticsearch 和 OpenSearch 是两个备受关注的选择.它们都以其出色的功能和灵活性而闻名,但在一些方面存在一些差异.在本文中,我们将从功能和延展性.工具与 ...

  2. 如何基于Perl实现批量蛋白名转换为基因名?以做后续GO与KEGG分析

    众所周知,在完成蛋白组学组间差异蛋白筛选后,往往要做GO与KEGG功能富集分析,这就需要我们首先将蛋白名转换为基因名,或者找出基因ID.将蛋白名转化为基因名可能涉及不同的转换工具或数据库,这里有几种常 ...

  3. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?

    Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的.而 Mybatis 在查询关联对象或关联集合 ...

  4. mysql 8.0 客户端

    1.mysql 8.0 command line client 2.mysql workbench

  5. Docker中部署单机Redis详细教程

    1.拉取Redis镜像 # 拉取redis镜像,不指定版本则默认是最新版本 docker pull redis 2.查看镜像 # 列出本地镜像 docker images 3.准备配置文件路径 # 创 ...

  6. 01-Python介绍、安装与入门

    Python介绍 关于Python Python 是一种解释型.面向对象.动态数据类型的高级程序设计语言. 解释型:Python将代码边解释边运行,而不是像C一样编译.类似解释型的语言还有JAVA. ...

  7. 防止unordered_map 被卡方法

    codeforces 上看到的,mark 一下代码.原作者:neal,原链接:https://codeforces.com/blog/entry/62393 struct custom_hash { ...

  8. 在Ubuntu 18.04 安装 adb

    Ubuntu下安装ADB 背景 电脑上的USB口有问题,不方便调试:发现用于开发的服务器就在工位旁边. 先拿过来用一下. Ubuntu:18.04 做法 安装adb 做法有很多种,列举下列2种. 下载 ...

  9. 中间件-Nginx

    一.nginx反向代理 输入 http://xxx.com/plat/login 跳转: http://localhost:8383/plat/login 将某个指定的域名代理到指定的服务 http: ...

  10. 在Mac上使用Emacs初步

    其他操作系统估计也差不多. 安装 如果使用brew就是brew install emacs.安装后不会在Applications里面显示一个程序,需要在命令行里执行emacs. 使用 进入和退出 上面 ...