[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. 《项目实战》从Spring开始说起

    引导 从今天开始,我们正式进入项目实战系列,我们会从项目架构的搭建,以及如何解决三高问题(高并发.高可用.高性能),源码会同步进行更新,欢迎大家持续关注 https://gitee.com/liupa ...

  2. 11条MySQL规范,你知道的有几个?

    一.数据库命令规范 · 所有数据库对象名称必须使用小写字母并用下划线分割 · 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) · 数据库对象的命名 ...

  3. 4个点说清楚Java中synchronized和volatile的区别

    作者 : Hollis 回顾一下两个关键字:synchronized和volatile 1.Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如sy ...

  4. python基础入门 字典

    字典 字典---->dict 字典是无序的,可变的 关联性强 键值对 键:使用不可变的数据类型(可哈希),键是唯一的 值:可以任意 定义一个字典 dic = {}#定义字典 ​ 字典的增删改查 ...

  5. 中文分词接口api,采用结巴分词PHP版中文分词接口

    中文分词,分词就是将连续的字序列按照一定的规范重新组合成词序列的过程.我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字.句和段能通过明显的分界符来简单划界,唯独词没有一个形式上 ...

  6. 《Java数据结构》链表结构(单向链表,双向链表)

    单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...

  7. HttpRunner学习9--切换测试报告模板

    前言 在HttpRunner中,给我们提供了 2 套测试报告模板,分别是 default_report_template.html 和 extent_report_template.html . 默认 ...

  8. Github挂载大文件解决方案

    正常情况下,我们上传代码之类的文本文件,都不会太大,可以直接通过[Upload Files]选项直接上传. 但是这样的操作仅限文件大小在25MB以内. 如果你选择的文件超过25MB,那么Github会 ...

  9. CSP-S 2019 游记

    目录 CSP-S 2019 游记 DAY -1 Day 0 Day 1 Day 2 后记 CSP-S 2019 游记 机房段子: zr(老师):yyx我看你最近不错哦(此人外号拳皇 yyx:运气好运气 ...

  10. 深度学习优质学习项目大放送!-AI Studio精选开源项目合集推荐

    近期 在AI Studio上发现了不少优质的开源深度学习项目,从深度学习入门到进阶,涵盖了CV.NLP.生成对抗网络.强化学习多个研究方向,还有最新的动态图,都以NoteBook的方式直接开源出来,并 ...