0x06 倍增
这东西太玄学了我真是不太会。。。
对于这道例题,很容易看出最大值必然是最大减最小,次大减次小……
常规的贪心思想,分的个数一样,总长度越大越好。
其实我的第一想法是二分右端点。。但是只有40,至今没有搞懂为什么倍增会比二分优秀,好玄学。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int n,m;LL k; LL a[510000],b[510000],tt[510000]; void mergesort(int l,int r) { if(l==r)return ; int mid=(l+r)/2; mergesort(l,mid);mergesort(mid+1,r); int i=l,j=mid+1,p=l; while(i<=mid&&j<=r) { if(b[i]<=b[j])tt[p++]=b[i++]; else tt[p++]=b[j++]; } while(i<=mid)tt[p++]=b[i++]; while(j<=r) tt[p++]=b[j++]; for(int i=l;i<=r;i++)b[i]=tt[i]; } int clen;LL c[510000]; bool check(int l,int r) { if(r>n)return false; int blen=r-l+1; for(int i=l;i<=r;i++)b[i-l+1]=a[i]; mergesort(1,blen); int i=1,j=1,p=1; while(i<=blen&&j<=clen) { if(b[i]<=c[j])tt[p++]=b[i++]; else tt[p++]=c[j++]; } while(i<=blen)tt[p++]=b[i++]; while(j<=clen)tt[p++]=c[j++]; p--; LL sum=0; for(int i=1;i<=m;i++) { if(p-i+1<=i)break; sum+=(tt[p-i+1]-tt[i])*(tt[p-i+1]-tt[i]); } if(sum<=k) { clen=p; for(int i=1;i<=clen;i++)c[i]=tt[i]; return true; } else return false; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%lld",&n,&m,&k); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); int ed,ans=0; for(int st=1;st<=n;st=ed+1) { ed=st;int L=1; clen=0;c[++clen]=a[st]; while(L>0) { if(check(ed+1,ed+L)==true) { ed=ed+L; L*=2; } else L/=2; } ans++; } printf("%d\n",ans); } return 0; }
st表就没什么好说的了,不过就是经常码错板子。。
pain and happy in the cruel world.