[CodeForces-1225B] TV Subscriptions 【贪心】【尺取法】

标签: 题解 codeforces题解 尺取法


题目描述

Time limit

2000 ms

Memory limit

262144 kB

Source

Technocup 2020 - Elimination Round 2

Tags

implementation  two pointers  *1300

Site

https://codeforces.com/problemset/problem/1225/B2

题面

Example

Input

4

5 2 2

1 2 1 2 1

9 3 3

3 3 3 2 2 2 1 1 1

4 10 4

10 8 6 4

16 9 8

3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3

Output

2

1

4

5

题目大意

给定\(n, k, d\)和序列\(a[1 \cdots n]\),\(1 \leq a[i] \leq k\)。问序列中连续\(d\)个数最少能有几个不同的数?

例如,

\(n = 5, k = 2, d = 2, a[1 \cdots 5] = [1, 2, 1, 2, 1]\)。连续的两个数只有\([1, 2], [2, 1]\)两种情况都是包含2个不同的数。所以输出2;

\(n = 9, k = 3, d = 3, a[1 \cdots 9] = [3, 3, 3, 2, 2, 2, 1, 1, 1]\)。当连续的三个数为\([3, 3, 3]\)时,包含的不同数的个数最少,为1个。若为其他,如\([2, 2, 1]\)或\([3, 2, 2]\),则包含2个不同的数。所以输出1。


解析

这道题用到了尺取法,尺取法在Codeforces中的标签是two pointers(双指针法)

但因为题目中规定了\(d\),即尺取的长度,两个指针只能一起移动,所以尺取的思想体现的不是很明显。

既然尺取的左右两个指针\(l, r\)如何移动的问题已经解决,那么接下来要解决的就是怎么维护尺取区间的信息?这道题是询问区间所包含的不同数字数最小。我们通过观察发现,每次\(l, r\)向右移动一位其实区间中只有两个变化,一个是先前\(l\)所指的数字出队,另一个是当前\(r\)所指的数字入队。那么我们只需查看这两个数字的一出一入对队列中不同数字数产不产生影响就可以了。这样我们就通过数组\(vis[1 \cdots k]\)来记录尺取区间中每个数字出现的次数。

  • 如果\((++ vis[a[r]]) = 1\),那么不同数字数就加一。
  • 如果\((-- vis[a[l - 1]]) = 0\),那么不同数字数就减一。

这样尺取区间从最左端滑到最右端,记录下不同数字数的最大值即是答案。该方法的时间复杂度是\(O(n)\)。

因为有多组输入,所以我们每次都要给数组\(vis\)归零。注意,数组归零的时候,如果使用k,循环k次会TLE。


通过代码

/*
Status
Accepted
Time
31ms
Memory
7836kB
Length
937
Lang
GNU G++11 5.1.0
Submitted
2019-12-17 21:52:46
RemoteRunId
67074221
*/ #include <bits/stdc++.h>
using namespace std; const int MAXN = 1e6 + 50;
int vis[MAXN], a[MAXN], n, k, d; inline int read() //快读,因为是2e5的输入量,所以加快读能明显提高程序速度.
{
int res = 0, f = 1;
char ch; ch = getchar(); while(!isdigit(ch)){
if(ch == '-')
f = -1; ch = getchar();
}
while(isdigit(ch)){
res = (res << 3) + (res << 1) + ch - 48;
ch = getchar();
} return f * res;
} void mem0() //vis数组归零函数.
{
for(int i = 1; i <= n; i ++) //注意这里要循环n次而不是k次,否则会超时.
vis[a[i]] = 0; return ;
} int main()
{
int times;
times = read(); while(times --){ int minn = 0, cnt = 0;
mem0(); n = read(), k = read(), d = read(); for(int i = 1; i <= n; i ++){
a[i] = read();
}
for(int i = 1; i <= d; i ++){ //先将最左端的d个数加入区间,构造好尺取区间.
if(!vis[a[i]]) cnt ++;
vis[a[i]] ++;
}
minn = cnt;
for(int i = d + 1; i <= n; i ++){ if(!vis[a[i]]) cnt ++; //注意这里并没有真的使用l,r指针(下标),因为l,r的移动是同时的,所以我们就用循环的i代替r,i-d代替l-1.
vis[a[i]] ++; vis[a[i - d]] --;
if(!vis[a[i - d]]) cnt --; minn = min(minn, cnt); //每次移动一位之后,看是否可以更新最小值. } printf("%d\n", minn);
}
return 0;
}

[CodeForces-1225B] TV Subscriptions 【贪心】【尺取法】的更多相关文章

  1. CodeForces 701C They Are Everywhere 尺取法

    简单的尺取法…… 先找到右边界 然后在已经有了所有字母后减小左边界…… 不断优化最短区间就好了~ #include<stdio.h> #include<string.h> #d ...

  2. codeforces #364c They Are Everywhere 尺取法

    C. They Are Everywhere time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  3. codeforces 652C C. Foe Pairs(尺取法+线段树查询一个区间覆盖线段)

    题目链接: C. Foe Pairs time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  4. luogu P1712 [NOI2016]区间 贪心 尺取法 线段树 二分

    LINK:区间 没想到尺取法. 先说暴力 可以发现答案一定可以转换到端点处 所以在每个端点从小到大扫描线段就能得到答案 复杂度\(n\cdot m\) 再说我的做法 想到了二分 可以进行二分答案 从左 ...

  5. Codeforces 650B Image Preview(尺取法)

    题目大概说手机有n张照片.通过左滑或者右滑循环切换照片,滑动需要花费a时间:看一张照片要1时间,而看过的可以马上跳过不用花时间,没看过的不能跳过:有些照片要横着看,要花b时间旋转方向.那么问T时间下最 ...

  6. Codeforces 660C Hard Process(尺取法)

    题目大概说给一个由01组成的序列,要求最多把k个0改成1使得连续的1的个数最多,输出一种方案. 和CF 676C相似. #include<cstdio> #include<algor ...

  7. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B. TV Subscriptions 尺取法

    B2. TV Subscriptions (Hard Version) The only difference between easy and hard versions is constraint ...

  8. Codeforces Educational Codeforces Round 5 D. Longest k-Good Segment 尺取法

    D. Longest k-Good Segment 题目连接: http://www.codeforces.com/contest/616/problem/D Description The arra ...

  9. Codeforces Round #364 (Div.2) C:They Are Everywhere(双指针/尺取法)

    题目链接: http://codeforces.com/contest/701/problem/C 题意: 给出一个长度为n的字符串,要我们找出最小的子字符串包含所有的不同字符. 分析: 1.尺取法, ...

随机推荐

  1. 新手学习FFmpeg - 如何编写Kubernetes资源文件

    Kubernetes API的使用方式 Kubernetes API属于声明式API编程, 它和常用的命令式编程有一些区别. 通俗的说,命令式编程是第一人称,我要做什么,我要怎么做. 操作系统最喜欢这 ...

  2. 【Nodejs】392- 基于阿里云的 Node.js 稳定性实践

    前言 如果你看过 2018 Node.js 的用户报告,你会发现 Node.js 的使用有了进一步的增长,同时也出现了一些新的趋势. Node.js 的开发者更多的开始使用容器并积极的拥抱 Serve ...

  3. Ambari 自定义服务集成原理介绍

    之前,在 github 上开源了 ambari-Kylin 项目,可离线部署,支持 hdp 2.6+ 及 hdp 3.0+ .github 地址为:https://github.com/8418090 ...

  4. 3年java开发竟然还不知道Lambda的这个坑

    背景 有朋友反馈zk连接很慢.整理出zk连接的关键逻辑如下: 上面的代码造成第一次调用ClientZkAgent.getInstance的时候,需耗时10s, 这个时间恰好跟semaphore的超时时 ...

  5. typeof 与 instanceof之间的区别

    JS中会使用typeof 和 instanceof来判断一个变量是否为空或者是什么类型的. ES6规范中有7种数据类型,分别是基本类型和引用类型两大类 基本类型(简单类型.原始类型):String.N ...

  6. 剑指Offer-46.孩子们的游戏(圆圈中最后剩下的数)(C++/Java)

    题目: 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机指定 ...

  7. DataTable和DataReader的遍历

    1.DataTable的遍历 //创建数据表 DataTable dt = GetDataTable("select * from Student"); //存储数据 String ...

  8. Scrum Meeting - 第七周【Alpha阶段】

    每日任务内容: 本次会议为第七次Scrum Meeting会议 本次会议项目经理召开时间为20:00,在北区男生宿舍楼召开,召开时长约10分钟,探讨了本周选课网站编写的后续工作. 小组成员 本周任务 ...

  9. MySQL数据库~~~~初识、基础数据类型

    一 数据库初识 1.1 什么是数据库 数据库(DataBase,简称DB),简而言之可视为电子化的文件柜----存储电子文件的处所,用户可以对文件中的数据运行新增,截取,更新,删除等操作. 所谓数据库 ...

  10. sqlserver update join 多关联更新

    由于程序bug,导致之前很多数据入库后信息不全,好在有基础信息表,可以通过基础信息表更新缺失字段信息 1.通过 inner join语法实现多关联更新 update a set a.name = b. ...