[CodeForces-1225B]テレビのサブスクリプション[貪欲] [サイズは、エミュレート]

[CodeForces-1225B]テレビのサブスクリプション[貪欲] [サイズは、エミュレート]

タグ:問題解決codeforcesの説明の足は、エミュレート


タイトル説明

制限時間
2000ミリ秒の
メモリの制限
262144 kBの
ソース
Technocup 2020 -エリミネーションラウンド2
タグの
実装二つのポインタ* 1300
サイト
https://codeforces.com/problemset/problem/1225/B2

フェイス質問

CodeForces-1225B.png

例の
入力

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;
}


おすすめ

転載: www.cnblogs.com/satchelpp/p/12068814.html