[CodeForces-1225B]テレビのサブスクリプション[貪欲] [サイズは、エミュレート]
タグ:問題解決codeforcesの説明の足は、エミュレート
タイトル説明
制限時間
2000ミリ秒の
メモリの制限
262144 kBの
ソース
Technocup 2020 -エリミネーションラウンド2
タグの
実装二つのポインタ* 1300
サイト
https://codeforces.com/problemset/problem/1225/B2
フェイス質問
例の
入力
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
出力
2
1
4
5
効果の対象に
所与\(N、K、D \ ) と配列(A [1 \ N-cdots] \)\ \ ([I] \のLeq K \ 1 \のLeq A) 。Q連続シーケンス\(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\),即尺取的长度,两个指针只能一起移动,所以尺取的思想体现的不是很明显。
それは2フィートポインタ程度かかりますので\(L、R \)どのように問題を移動するために解決すべきその次、解決された情報フィートの範囲を取るためにいかに維持するかですか?この質問は含ま異なるデジタル尋問間隔の最小数です。我々は、各ことが観察され\(L、R \)実際には1ビット期間の2つだけ変更、以前に右\(L \)デジタルチームの意味の範囲内で、他方は電流である(\ R \ )チームの意義の範囲内の数字。その後、我々は単に単一の入力キューがその上に異なるデジタル製造番号に影響を与えていない2つの数値を確認してください。だから我々アレイを介していること\(VIS [1 \ cdots kは ] \) のレコードに足部の数は、各番号が表示されますを取ります。
- 場合((VIS ++ [A [R&LT])= 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;
}