赞
踩
题目链接:点击查看
题目大意:给出一个长度为 n 的序列,每个数字的范围是 [ 1 , C ] ,现在需要求一个子串,使得字串中的字母,要么出现 0 次,要么出现至少 K 次,问这个子串的最大长度是多少
题目分析:第一反应是二分+尺取,但感觉会超时,正解是线段树,枚举 1 ~ n 作为子串的右端点,然后贪心找符合条件的左端点
对于任意一个位置 i ,再对于任意一个数字 b 来说,设 pos1 是数字 b 从位置 i 向左开始第一次出现的位置,pos2 是第 k 次出现的位置,pos3 是第 k - 1 次出现的位置(下面会用到),则对于数字 b 来说,可以选择的左端点的区间范围是 [ 1 , pos2 ] 和 [ pos1 + 1 , i ]
这样当我们枚举位置 i 时,假设位置 i 的数字为 num ,其前一次出现的位置为 pre,则因为第 i 个位置是 num,所以区间 [ pre + 1 , i ] 这段区间对左端点的贡献集体减一,因为如果还没有第 i 个数字出现的话,那么对于数字 num 来说,区间 [ pre + 1 , i - 1 ] 这段区间对左端点的贡献都为 1 ,所以当加入第 i 个位置的 num 后,需要群体减一
同时,因为新加入了一个 num 的位置,所以原先 [ 1 , pos2 ] 的这段区间扩大到了 [ 1 , pos3 ] 这么大,相当于 [ pos2 + 1 , pos3 ] 这段区间对左端点的贡献集体加一了
因为对于贡献来说,既有群体加一,又有群体减一,所以当一个节点的相对贡献大于等于 0 时,说明当前节点可以选做为左端点,每次处理完后,贪心去寻找相对贡献大于等于 0 的最左端的位置,然后更新答案即可
代码:
- #include<iostream>
- #include<cstdio>
- #include<string>
- #include<ctime>
- #include<cmath>
- #include<cstring>
- #include<algorithm>
- #include<stack>
- #include<climits>
- #include<queue>
- #include<map>
- #include<set>
- #include<sstream>
- #include<cassert>
- using namespace std;
-
- typedef long long LL;
-
- typedef unsigned long long ull;
-
- const int inf=0x3f3f3f3f;
-
- const int N=1e5+100;
-
- vector<int>pos[N];
-
- struct Node
- {
- int l,r,mmax,lazy;
- }tree[N<<2];
-
- void pushup(int k)
- {
- tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
- }
-
- void pushdown(int k)
- {
- if(tree[k].lazy)
- {
- int lz=tree[k].lazy;
- tree[k].lazy=0;
- tree[k<<1].lazy+=lz;
- tree[k<<1].mmax+=lz;
- tree[k<<1|1].lazy+=lz;
- tree[k<<1|1].mmax+=lz;
- }
- }
-
- void build(int k,int l,int r)
- {
- tree[k].l=l;
- tree[k].r=r;
- tree[k].mmax=tree[k].lazy=0;
- if(l==r)
- return;
- int mid=l+r>>1;
- build(k<<1,l,mid);
- build(k<<1|1,mid+1,r);
- }
-
- void update(int k,int l,int r,int val)
- {
- if(tree[k].r<l||tree[k].l>r)
- return;
- if(tree[k].l>=l&&tree[k].r<=r)
- {
- tree[k].lazy+=val;
- tree[k].mmax+=val;
- return;
- }
- pushdown(k);
- update(k<<1,l,r,val);
- update(k<<1|1,l,r,val);
- pushup(k);
- }
-
- int query(int k)
- {
- if(tree[k].mmax<0)
- return inf;
- if(tree[k].l==tree[k].r)
- return tree[k].l;
- pushdown(k);
- if(tree[k<<1].mmax>=0)
- return query(k<<1);
- else
- return query(k<<1|1);
- }
-
- void init(int c)
- {
- for(int i=1;i<=c;i++)
- {
- pos[i].clear();
- pos[i].push_back(0);
- }
- }
-
- int main()
- {
- #ifndef ONLINE_JUDGE
- // freopen("data.in.txt","r",stdin);
- // freopen("data.out.txt","w",stdout);
- #endif
- // ios::sync_with_stdio(false);
- int n,c,k;
- while(scanf("%d%d%d",&n,&c,&k)!=EOF)
- {
- init(c);
- build(1,1,n);
- int ans=0;
- for(int i=1;i<=n;i++)
- {
- int num;
- scanf("%d",&num);
- update(1,pos[num].back()+1,i,-1);
- if(pos[num].size()>k)
- update(1,1,pos[num][pos[num].size()-k],-1);
- pos[num].push_back(i);
- if(pos[num].size()>k)
- update(1,1,pos[num][pos[num].size()-k],1);
- ans=max(ans,i-query(1)+1);
- }
- printf("%d\n",ans);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。