[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. iSensor APP 之 摄像头调试 OV9655 测试之二

    参考上一篇博客 iSensor APP 之 摄像头调试 OV9655 本次链接主要介绍,使用ov9655输出QVGA格式,320*240  YUV输出,图像效果还不错,用户可以参考此模板改变分辨率,不 ...

  2. 【Babel】293- 初学 Babel 工作原理

    戳蓝字「前端技术优选」关注我们哦! 前言 babel Babel 对于前端开发者来说应该是很熟悉了,日常开发中基本上是离不开它的. 已经9102了,我们已经能够熟练地使用 es2015+ 的语法.但是 ...

  3. Oracle - 通过dg,完成单实例到rac的迁移

    一.概述 本文将介绍如何给单实例搭建一个rac dg,以及如何对其进行角色转换,完成从单实例到rac的迁移.预先具备的知识(rac搭建,单实例-单实例dg搭建) 二.实验环境介绍 主库(已有数据库实例 ...

  4. Oracle 12C CDB、PDB常用管理命令

    Oracle 12C CDB.PDB常用管理命令 --查看PDB信息(在CDB模式下) show pdbs  --查看所有pdbselect name,open_mode from v$pdbs;  ...

  5. textarea增加字数监听且高度自适应(兼容IE8)

    1.封装方法: var textareaListener = { /*事件监听器兼容 * *attachEvent——兼容:IE7.IE8:不兼容firefox.chrome.IE9.IE10.IE1 ...

  6. 《Java练习题》进阶练习题(一)

    编程合集: https://www.cnblogs.com/jssj/p/12002760.html 前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题. [程序48 ...

  7. 如何"快准狠"找到内存相关的问题

    为了迅速定位内存问题,通常会先运行几个覆盖面比较大的性能工具,比如 free.top.vmstat.pidstat 等. 具体的分析思路主要有这几步 先用 free 和 top,查看系统整体的内存使用 ...

  8. WebGPU学习系列目录

    介绍 大家好,本系列从0开始学习WebGPU API,并给出相关的demo. WebGPU介绍 WebGPU相当于DX12/Vulkan,能让程序员更灵活地操作GPU,从而大幅提升性能. 为什么要学习 ...

  9. JS---DOM---为元素解绑事件

    解绑事件 注意:用什么方式绑定事件, 就应该用对应的方式解绑事件 1.解绑事件 对象.on事件名字=事件处理函数--->绑定事件 对象.on事件名字=null;   //1 对象.on事件名字= ...

  10. Flutter报错记录

    1.Could not find an option named "androidx". Run 'flutter -h' (or 'flutter   -h') for avai ...