CF786C Till I Collapse
题目大意:
对于一个序列,倘若一个区间内最多能发 $k$ 个不同的数,那么这个序列最少被划分成几个区间。
输出 $k$ 为 $1$ ~ $n$ 的答案。
思路:
其实会有连续一段不同的 $k$ 得到相同的答案,所以我们对于每段 $k$ 向下递归,如果左端点的答案和右端点的答案相同,那么就可以确定这一整段区间的答案。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e5+5; bool vis[N]; int n,a[N],ans[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int getans(int k){ int num=0,res=0,l=1; for(int i=1;i<=n;i++){ if(!vis[a[i]]){ num++; if(num>k){ num=1; for(int j=l;j<i;j++)vis[a[j]]=0; res++;l=i; } vis[a[i]]=1; } } for(int i=1;i<=n;i++)vis[i]=0; return res+1; } il void solve(int l,int r){ if(!ans[l])ans[l]=getans(l); if(!ans[r])ans[r]=getans(r); if(ans[l]==ans[r]){ for(int i=l;i<=r;i++)ans[i]=ans[l]; return; } int mid=(l+r)>>1; solve(l,mid);solve(mid+1,r); } int main() { n=read(); for(int i=1;i<=n;i++)a[i]=read(); solve(1,n); for(int i=1;i<=n;i++)printf("%d ",ans[i]); return 0; }