【解题报告】 天才ACM
题目:天才ACM
解题思路:
倍增算法
设p=1,r=l
求出r—r+p这一区间的校验值,如果校验值小于等于t,则r+=p,p*=2;
否则p/=2;
一直重复,直到p等于0的时候,r就是最终答案
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=500005;
long long t,tot;
long long n,m,k;
long long p[maxn];
long long f[maxn];
int l,r,mid,j;
long long min(long long a,long long b)
{
return a<b? a:b;
}
bool check(int l,int r)
{
tot=0;
long long sum=0;
for(int i=l;i<=r;i++)
f[++tot]=p[i];
sort(f+1,f+1+tot);
for(int i=1;i<=m;i++)
{
if (i>=(tot-i+1))
break;
sum+=(long long)(f[tot-i+1]-f[i])*(f[tot-i+1]-f[i]);
if(sum>k)
break;
}
if(sum>k)
return false;
return true;
}
bool cmp(int x,int y)
{
return p[x]<p[y];
}
bool calc()
{
long long sum=0;
int ll=1,rr=tot;
for(int i=1;i<=m;i++)
{
while(ll<rr&&f[ll]>mid)
ll++;
while(ll<rr&&f[rr]>mid)
rr--;
if(ll>=rr)
break;
sum+=(long long)(p[f[rr]]-p[f[ll]])*(p[f[rr]]-p[f[ll]]);
if(sum>k)
break;
ll++;
rr--;
}
return sum<=k;
}
void work()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
cin>>p[i];
int ans=0;
for(int i=1;i<=n;i++)
{
for(j=1;i+(1<<j)-1<=n;j++)
{
if(!check(i,i+(1<<j)-1))
break;
}
l=i+(1<<(j-1))-1;
r=min(i+(1<<j)-1,n);
tot=0;
for(int k=i;k<=r;k++)
f[++tot]=k;
sort(f+1,f+tot+1,cmp);
while(l<=r)
{
mid=(l+r)/2;
if(calc())
{
i=mid;
l=mid+1;
}
else r=mid-1;
}
ans++;
}
cout<<ans<<endl;
}
int main()
{
cin>>t;
while(t--)
{
work();
}
return 0;
}