#C220816C. 时间复杂度
#C220816C. 时间复杂度
C220816C 校内模拟赛
背景
注意:本题采用捆绑测试。
题目描述
在你的帮助下,小凯成功找到了宝藏价值最大的方案。接下来他在闲逛时被一个游戏机吸引了。
游戏机中共有
- 要么在这个区间中出现
次(即不出现); - 要么在这个区间中出现次数
。
其中
小凯想用 OI 知识解决这个问题,但是由于水平问题,他只会
即求出,最长满足要求的区间长度是多少。特别的,若问题无解,输出
输入格式
第一行共一个数
第二行共
第三行共
输出格式
输出共一个数字,表示最长的合法区间长度。
样例
输入数据 1
7
2 0 4 0 4 3 2
3 3 3 2 2 2 2
输出数据 1
4
样例说明
选
数据规模与约定
subtask1(10pts) :n≤300。
subtask2(15pts) :n≤1500。
subtask3(20pts) :n≤100000。
subtask4(20pts) :保证所有
subtask5(35pts) :无特殊限制。
对于
Tips: 由于输入输出量较大,建议使用快速输入输出。
Solution
题目中有一个及其重要的条件,就是
假如有一个区间
将原序列作为一个大区间,然后在这个大区间中找到所有导致这个大区间不合法的
用样例来解释,第一轮:
划分成为:
这两个区间,然后递归进入这两个区间(右侧那个单
划分成为:
再次递归进入新的小区间,发现是一个合法的区间,更新答案。
可以得知每个数出现次数总共有
考虑怎么优化这种做法。不难发现可以将一次找完大区间内所有的
为了使找
Code
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
void read(auto &k)
{
k=0;auto flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
void write(auto x) {if (x<0) {putchar('-');write(-x);return;}if (x>9) write(x/10);putchar(x%10+'0');}
void writewith(auto x,char c) {write(x);putchar(c);}
const int _SIZE=1e6;
int n,a[_SIZE+5],b[_SIZE+5];
int cnt[_SIZE+5],res;//cnt是桶,res记录答案
void calc(int l,int r)
{
if (r<l || r-l+1<=res)//如果区间非法或者是比答案小,那么直接清除贡献
{
for (int i=l;i<=r;i++) --cnt[a[i]];
return;
}
if (l==r)//单点,更新答案后清除贡献
{
--cnt[a[l]];
if (b[1]==1) res=max(res,1);
return;
}
int p=l,q=r,pos=-1,target=b[r-l+1];
while (p<=q)//双指针寻找pos值
{
if (cnt[a[p]]<target) {pos=p;break;}
if (cnt[a[q]]<target) {pos=q;break;}
q--,p++;
}
if (pos<0)//不存在pos值
{
res=max(res,r-l+1);//更新答案
for (int i=l;i<=r;i++) --cnt[a[i]];//清除贡献
return;
}
if (pos<=((l+r)>>1))//pos靠左,左侧为小区间
{
for (int i=l;i<=pos;i++) --cnt[a[i]];//清除左侧小区间贡献
calc(pos+1,r);//计算右侧贡献
for (int i=l;i<pos;i++) ++cnt[a[i]];//计算左侧贡献
calc(l,pos-1);
}
else
{
for (int i=pos;i<=r;i++) --cnt[a[i]];//同上
calc(l,pos-1);
for (int i=pos+1;i<=r;i++) ++cnt[a[i]];
calc(pos+1,r);
}
}
signed main()
{
read(n);
for (int i=1;i<=n;i++) read(a[i]),cnt[a[i]]++;
for (int i=1;i<=n;i++) read(b[i]);
calc(1,n);//原序列直接作为大区间
writewith(res,'\n');
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步