CF1446D. Frequency Problem
题目大意
长为n的序列,求最长众数非唯一子串长度
n<=2e5,ai<=n
D1:ai<=min(100,n)
题解
D1:
枚举右端点,显然随着左端点不断右移,一定有某个时刻众数非唯一,因此求出当前众数与其他的相等的最小l之后对长度取max
每次+1-1只会改变1所以用桶维护,因为不好直接存所以写了链表
实际上只需要考虑[1,n]的众数即可,比赛时并没有注意到虽然也能过
D2:
首先写一个空间线性的D1,然后平衡规划,这样是O(n√n)
然后又被ll爆标了
D1的瓶颈在于每次要把所有的值找一遍,现在按非众数来分段,那么总数就是O(n)的
设众数为+1,非众数为-1
之后+1变成段,-1变成点,对每种值维护这个东西,跳就暴力跳,因为跳-1的次数为O(n),跳+1直到跳到当前max的次数和-1相当(把-1看作势能),也是O(n)
如果当前是-1就记下位置,否则位置一定是某个众数的位置,把众数提出来后记是第几个即可
先给每种权值分配好空间,之后就可以时空O(n)解决
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define ll long long
//#define file
using namespace std;
int Sum[200002],sum[200002],a[200002],L[200002],R[200002],n,i,j,k,l,mx,mx2,ans;
int ls[200002],d[800001][2],b[200002],c[200002],f[800001],I[200002],id[200002];
int get(int t,int x)
{
if (f[t]<=0) return -f[t];
return I[f[t]+(x-d[t][0])];
}
void work(int i,int s)
{
int j,k,l;
l=sum[i]-sum[ls[s]];
while (l && b[s]<=R[s])
{
k=get(b[s],c[s]),ans=max(ans,(I[id[s]+1]-1)-k);
if (c[s]==d[b[s]][1]) ++b[s];
--l,++c[s],++id[s];
}
if (b[s]>R[s]) ++R[s],d[R[s]][0]=d[R[s]-1][1]+1,d[R[s]][1]=c[s]+l,f[R[s]]=id[s],id[s]+=l,c[s]+=l;
k=get(b[s],c[s]),ans=max(ans,(i-1)-k);
if (i<=n)
{
if (c[s]==d[b[s]][0])
{
if (b[s]==L[s])
{
--L[s];
d[L[s]][0]=d[L[s]][1]=d[L[s]+1][0]-1;
f[L[s]]=-i;
}
--b[s];
}
--c[s];
}
ls[s]=i;
}
int main()
{
#ifdef file
freopen("CF1446D.in","r",stdin);
// freopen("b.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&a[i]),++Sum[a[i]];
if (Sum[a[i]]>mx) mx=Sum[a[i]],mx2=a[i];
}
fo(i,1,n+1) sum[i]=sum[i-1]+(a[i]==mx2);
k=l=0;
fo(i,1,n)
if (i!=mx2)
b[i]=l+(Sum[i]+1),L[i]=R[i]=b[i],c[i]=0,d[b[i]][0]=d[b[i]][1]=0,l+=Sum[i]*2+2;
fo(i,1,n) if (a[i]==mx2) I[++k]=i;
fo(i,1,n) if (a[i]!=mx2) work(i,a[i]);
fo(i,1,n) if (i!=mx2) work(n+1,i);
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}