[UOJ#206][Apio2016]Gap(分块+数学相关)

题目描述

传送门

题解

去年Apio回来写了这道题,今天看被ATP和hxy两位大爷怒切了,于是赶来补一发题解

30pts

注意到是“严格上升”的序列
每一次查询当前区间的mn,mx,然后左右指针往里缩,这样就能在 N+12 的次数之内得到整个序列

70pts

首先查询一下整个定义域,找到整个数列的mn和mx
将[mn,mx]划分成N块,每块长度为 mxmnN
可以发现最大值一定不会出现在块内,跨块的话一定是一个块的最大值和另一个块的最小值
所以对于每一个块找mn和mx就行了
这样的话,最大值和最小值点被查询了1次,剩余的点被查询了2次,而总的查询次数是N+1,所以费用为2+(N-2)*2+N+1=3N-1,正好符合要求

代码

#include "gap.h"
#include
#include
#include
#include
using namespace std;
long long a[500005]={0};
long long findGap(int T, int N)
{
    if (T==1)
    {
        int l=1,r=N;
        long long Min=0,Max=1e18,mn,mx,ans=0;
        while (l<=r)
        {
            MinMax(Min,Max,&mn,&mx);
            a[l]=mn; a[r]=mx;
            l++; r--;
            Min=mn+1; Max=mx-1;
        }
        for (int i=1;iif (ans1]-a[i])
                ans=a[i+1]-a[i];

        return ans;
    }
    else
    {
        long long Min=0,Max=1e18,mn,mx,L,l,r,ans=0;
        bool flag=false;
        int n=0;
        MinMax(Min,Max,&mn,&mx);
        if ((mx-mn)%N!=0) L=(mx-mn)/N+1;
        else L=(mx-mn)/N;
        Min=mn; Max=mx-1; a[++n]=mn;
        while (!flag)
        {
            l=Min+1;
            r=Min+L;
            if (r>=Max)
            {
                r=Max;
                flag=true;
            }
            if (l<=r) MinMax(l,r,&mn,&mx);
            if (mn!=-1&&mx!=-1)
                a[++n]=mn,a[++n]=mx;
            Min+=L;
        }
        a[++n]=Max+1;
        for (int i=1;iif (ans1]-a[i])
                ans=a[i+1]-a[i];

        return ans;
    }
}

你可能感兴趣的:(题解,数学相关,分块,非传统题)