[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. 基于STM32F1 的BASIC解码实验 vb basic 液晶显示执行过程及结果

    基于STM32F1 的BASIC解码实验 1.basic程序以文件形式存储 2.程序文件存储在sd卡 3.解释结果显示在液晶屏上 主函数部分 int main(void){ u16 i,j; dela ...

  2. 每周一练 之 数据结构与算法(LinkedList)

    这是第三周的练习题,原本应该先发第二周的,因为周末的时候,我的母亲大人来看望她的宝贝儿子,哈哈,我得带她看看厦门这座美丽的城市呀. 这两天我抓紧整理下第二周的题目和答案,下面我把之前的也列出来: 1. ...

  3. postman接口测试工具的常规使用

    目录 postman接口测试工具简介与安装 postman发送get请求 JSON数据详解 postman发送post请求 postman中post请求传参说明 postman设置请求的header ...

  4. 从多谐振荡器详细解析到555定时器基本电路(控制LED闪烁)

    在学期末,笔者参加了学校的电工实习,前六天做都很快,但是今天要做一个关于555多谐振荡器的LED闪烁电路,由于笔者没有提前准备,导致今天就算把电路搭建出来也不懂具体原理,耗费了不少时间,所以我打算专门 ...

  5. LeetCode 1290. 二进制链表转整数

    地址 https://www.acwing.com/solution/LeetCode/content/7132/ 题目描述给你一个单链表的引用结点 head.链表中每个结点的值不是 0 就是 1.已 ...

  6. 从多核CPU Cache一致性的应用到分布式系统一致性的概念迁移

    概述 现代多核CPU的cache模型基本都跟下图1所示一样,L1 L2 cache是每个核独占的,只有L3是共享的,当多个cpu读.写同一个变量时,就需要在多个cpu的cache之间同步数据,跟分布式 ...

  7. 中国 700 万开发者中,370 万在使用 VS Code

    近日(2019 年 12 月 10 日 - 11 日),Microsoft Ignite The Tour 北京站圆满落幕. 微软大中华区副总裁.市场营销及运营总经理康容先生,在大会上表示:“在中国 ...

  8. AQS系列(六)- Semaphore的使用及原理

    前言 Semaphore也是JUC包中一个用于并发控制的工具类,举个常用场景的例子:有三台电脑五个人,每个人都要用电脑注册一个自己的账户,这时最开始只能同时有三个人操作电脑注册账户,这三个人中有人操作 ...

  9. 人员简历管理系统-毕业设计(包括文档+源代码+答辩PPT)

    1.开发环境 开发工具:Microsoft Visual Studio 2010操作系统:Windows7(推荐)或更高版本 数据库:sql server 2000 或者更高版本Web服务器:IIS ...

  10. uni-app实现多端开发

    多端开发,听名字就感觉不一样,一套代码.多端使用,适用于各个平台.市面上很多关于多端开发的框架,比较常用,流行的框架 uni-app,Chameleon(变色龙),taro这些,都可以支持多端,一套代 ...