码迷,mamicode.com
首页 > 其他好文 > 详细

XJ7191 Genius ACM

时间:2019-07-15 16:04:58      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:注意   pre   元素   ace   hellip   有序   答案   def   problem   

二分+倍增

题目

题目中的最大校验值应由数组排序后,取出最大值和最小值,次大值和次小值……进行做差平方取和

所以在加入一个新的数时,校验值是不会下降的

那么可以发现,校验值是单调递增的,所以可以用二分对每一个固定的左段点找到满足条件的最大的右端点

所以l初始值设为1,不断对r进行二分,找到最大的点

进行二分时要用二进制数(倍增),不能直接取mid

设一个偏量p,右端点即为r+p,一开始设为1,然后对其判断,在k的范围内p就乘2,否则p除以2

进行判断时,将整个区间进行排序,取前m个数和后m个数分别做差,算出值与k比较

但此时时间复杂度为O(n*logn*logn),对于n=5*1e5是过不了的

而排序用的时间最多,所以要利用之前排好的元素进行归并排序

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN=5*1e5+100;
ll t,n,m,k,a[MAXN],b[MAXN],p;
ll ans,c[MAXN];
bool check(ll l,ll r)
{
    ll tot=0;
    for (ll i=0;i<m;i++)
    {
        if (l+i>r-i)
          break;
        tot+=(c[l+i]-c[r-i])*(c[l+i]-c[r-i]);
    }
    return tot<=k;
}
void merge(ll la,ll ra,ll lb,ll rb)//合并两个有序数组
{
    ll l,r,now;
    l=la;
    r=lb;
    now=la-1;
    while (l<=ra && r<=rb)
    {
        if (b[l]<=b[r])
        {
            now++;
            c[now]=b[l];
            l++;
        }
        else
        {
            now++;
            c[now]=b[r];
            r++;
        }
    }
    for (ll i=l;i<=ra;i++)
    {
        now++;
        c[now]=b[i];
    }
    for (ll i=r;i<=rb;i++)
    {
        now++;
        c[now]=b[i];
    }
}
int main()
{
    scanf("%lld",&t);
    while (t--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        for (ll i=1;i<=n;i++)
          scanf("%lld",&a[i]);
        ll l,r;
        l=1;
        ans=0;
        while (l<=n)
        {
            ans++;//统计答案
            p=1;
            r=l;
            b[l]=a[l];
            while (p)
            {
                if (r+p>n)
                {
                    p>>=1;
                    continue;
                }
                for (int i=r+1;i<=r+p;i++)//r之前的元素已经排好了序,所以对[r+1,r+p]的元素排序
                  b[i]=a[i];
                sort(b+r+1,b+r+p+1);
                merge(l,r,r+1,r+p);//将两个区间的元素合并
                if (check(l,r+p))
                {
                    for (int i=l;i<=r+p;i++)//注意,这句不能放在merge函数中,因为p有可能变小,之前排好序的元素可能排到了r之后,在之后统计答案时无法统计到
                      b[i]=c[i];
                    r+=p;
                    p<<=1;
                }
                else
                {
                    p>>=1;
                }
            }
            l=r+1;
        }
        printf("%lld\n",ans);
    }
}

 

XJ7191 Genius ACM

标签:注意   pre   元素   ace   hellip   有序   答案   def   problem   

原文地址:https://www.cnblogs.com/huangchenyan/p/11189370.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!