JZOJ 100046. 【NOIP2017提高A组模拟7.14】收集卡片
Description
Star 計劃訂購一本將要發行的周刊雜志,但他可不是為了讀書,而是—— 集卡。 已知雜志將要發行 N 周(也就是 N 期),每期都會附贈一張卡片。Star 通 過種種途徑,了解到 N 期雜志附贈的卡片種類。Star 只想訂購連續的若干期, 并在這些期內收集所有可能出現的種類的卡片。現在他想知道,他最少需要訂 購多少期。
Input
第一行一個整數 N;
第二行一個長度為 N 的字符串,由大寫或小寫字母組成,第 i 個字符表示 第 i 期附贈的卡片種類,每種字符(區分大小寫)表示一種卡片。
Output
輸出一行一個整數,表示 Star 最少訂購的期數。
Sample Input
8
acbbbcca
Sample Output
3
Data Constraint
對于 30%的數據,N ≤ 300;
對于 40%的數據,N ≤ 2000;
對于 60%的數據,N ≤ 5000;
對于 80%的數據,N ≤ 100000;
對于 100%的數據,N ≤ 500000。
Solution
這題的題意就是給你一段包含多種元素序列,求最短的一段連續的區間包含所有種類的元素。
那么就有各種解決的方法了,我的方法是 O(NlogN) 的。(聽說 O(N) 掃一遍就可以了)
先二分答案 Mid ,把原問題轉化成判定性問題。
在將長為 Mid 的區間一格一格地從左向右移動,一邊加進一個新元素,一邊刪去。
中途用一個標志數組 Bz[i] 表示 i 這個字母在區間中出現的多少次,
并維護包含的元素種類是否達到全部即可,這樣的復雜度是 O(N) 。
再結合上二分,總時間復雜度就是 O(NlogN) ,秒過本題。
Code
#include<cstdio> #include<cstring> using namespace std; int n,num; int a[500001],bz[150]; int main() {scanf("%d",&n);for(int i=1;i<=n;i++){char ch=getchar();while(!('A'<=ch && ch<='Z' || 'a'<=ch && ch<='z')) ch=getchar();if(++bz[a[i]=ch]==1) num++;}int l=1,r=n;while(l<r){int mid=(l+r)>>1,k=0;memset(bz,0,sizeof(bz));for(int i=1;i<=mid && k<num;i++)if(++bz[a[i]]==1) k++;if(k==num){r=mid;continue;}for(int i=mid+1;i<=n && k<num;i++){if(++bz[a[i]]==1) k++;if(!--bz[a[i-mid]]) k--;}if(k==num) r=mid; else l=mid+1;}printf("%d",l);return 0; }總結
以上是生活随笔為你收集整理的JZOJ 100046. 【NOIP2017提高A组模拟7.14】收集卡片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 100045. 【NOIP20
- 下一篇: JZOJ 100047. 【NOIP20