cf1120 A. Diana and Liana(思維,定長的雙指標)
阿新 • • 發佈:2021-12-20
題意:
把長為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\) 的合法區間。開桶記錄區間中每個數出現的次數 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; }