CF786C Till I Collapse
阿新 • • 發佈:2021-07-20
題目分析
首先,對於這道題,可以用貪心以一個\(O(n)\)的複雜度求解一個\(k\)的值
暴力是\(O(n^2)\)的複雜度,當然過不了。
我們手推一下樣例,會發現,答案滿足單調性,於是,果斷想到二分。
再推一推性質,會發現,實際上,一個答案最多會出現\(\sqrt n\)次,於是,可以對答案分塊,用二分列舉右邊界,時間複雜度\(O(n\sqrt nlog(n))\),還是過不了。
但因為每一次一個答案最多會出現\(\sqrt n\)次,這就是塊的最大長度。
於是,對於\(k\le\sqrt n\)的部分,可以暴力,最後,卡卡常就過了。
對於每一個數,可以記錄出現的最大塊,看是否在當前塊出現,這樣就避免了在算 \(k\)
#include<bits/stdc++.h> using namespace std; int n; int a[100005]; int tot[100005]; int size; int check(int mid) { int now=1; int cout=0; for(int i=1;i<=n;i++) { if(tot[a[i]]!=now) { cout++; tot[a[i]]=now; } if(cout>mid) { cout=1; now++; tot[a[i]]=now; } } return now; } int main() { scanf("%d",&n); size=sqrt(n*log2(n)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=size;i++) { int now=1; int cout=0; memset(tot,0,sizeof(tot)); for(int j=1;j<=n;j++) { if(tot[a[j]]!=now) { cout++; tot[a[j]]=now; } if(cout>i) { cout=1; now++; tot[a[j]]=now; } } printf("%d ",now); } int l=size+1; int r; while(l<=n) { int now=1; int cout=0; memset(tot,0,sizeof(tot)); for(int i=1;i<=n;i++) { if(tot[a[i]]!=now) { cout++; tot[a[i]]=now; } if(cout>l) { cout=1; now++; tot[a[i]]=now; } } int L=l; int R=n; while(L<=R) { int mid=(L+R)>>1; memset(tot,0,sizeof(tot)); int tc=check(mid); if(tc>=now) { L=mid+1; r=mid; } else { R=mid-1; } } for(int i=l;i<=r;i++) { printf("%d ",now); } l=r+1; } }