1. 程式人生 > 其它 >cf1120 A. Diana and Liana(思維,定長的雙指標)

cf1120 A. Diana and Liana(思維,定長的雙指標)

題意:

把長為m的陣列分為n個長為k的區間 \([a_1,a_{k}],[a_{1+k},a_{2k}],\cdots , [a_{1+(n-1)k},a_{nk}]\) ,多出來的 \([a_{nk},a_m]\) 不用管。題目保證一定夠分。現在可以刪除若干個數,使得至少有一個區間中,\(b_i\) 至少出現一次,且總區間數仍為n。b陣列可能有重複值,表示某個數要出現至少多次。求刪數方案。

思路:

\(O(n)\) 這題思路很簡單,比那種不定長的雙指標簡單多了。但我碼力不行,寫得很慢。

最多可以刪掉 \(m-kn\) 個數,所以可以把原陣列分為 \(n-1\) 個長為 \(k\) 的區間和 \(1\)

個長為 \(len=k+(m-kn)\) 的區間。

接下來只需看是否存在長為 \(len\) 的合法區間。開桶記錄區間中每個數出現的次數 have[a[i]],雙指標更新左右端點和桶,並與每個數需要的數量 need[a[i]] 比較。注意不是所有的長為 \(len\) 的區間都能取,左端點必須為 \(1+ik\) 的形式。

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n, m, k, s, a[N];
int need[N], have[N], types;
void output(int l, int r)
{
    vector<int> ans; int len = r - l + 1;
    for(int i = l; len > k && i <= r; i++)
        if(have[a[i]] > need[a[i]]) ans.push_back(i), have[a[i]]--, len--;
    printf("%d\n", ans.size());
    for(int i : ans) printf("%d ", i);
}
signed main()
{
    scanf("%d%d%d%d", &m, &k, &n, &s);
    for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
    for(int i = 1; i <= s; i++)
    {
        int x; scanf("%d", &x);
        if(++need[x] == 1) types++;
    }

    int len = k + m - k * n, typecnt = 0;
    for(int i = 1; i <= len; i++)
        if(++have[a[i]] == need[a[i]]) typecnt++;

    for(int l = 1, r = len; r <= m; l += 1, r = l + len - 1)
    {
        if((l-1)%k == 0 && typecnt == types) return output(l, r), 0;

        if(r == m) return puts("-1"), 0;

        if(++have[a[r+1]] == need[a[r+1]]) typecnt++;
        if(--have[a[l]] == need[a[l]] - 1) typecnt--;
    }

    return 0;
}