【CSP】202112-2 序列查询新解

题目大意:

给定一长度为n+1的严格单增数列A[a0,a1,a2,a3...,an],其中a0=0,an<N

定义f(x)为数列A中小于等于x的最大整数的下标,r=floor(N/(n+1)),g(x)=floor(x/r)。

当N<1e9,n<1e4的时候,求解|g(x)-f(x)|之和,x=0,1,2...,N-1

 

分析:

数据规模较大,如果一项一项求和将会超时。

为优化朴素方法,观察求和式,发现由于g(x)向下取整的性质,在数轴上呈现为长度为r的阶梯上升状;同样由于f(x)的性质,在数轴上呈现为每个数列元素处上升1的阶梯状。

同时可以发现,如果按照数列元素而不是每个整数求和,复杂度将会大大降低。

结合以上两点,可以分析出f(x)和g(x)可以分别单独在区间上直接计算,并且a_x~a_x+1之间函数g(x)-f(x)存在至多一个零点,可以以此性质在同号区间内去掉绝对值符号,直接计算f(x)和g(x)的区间值。

 

代码:

先写出任意两点间计算g(x)之和的函数,再写出如果存在零点如何分割区间的函数,最终获得结果。

#include <cstdio>
#include <iostream>
#include <algorithm>

#define up(l,r,i) for(int i=l;i<=r;i++)
#define dn(l,r,i) for(int i=r;i>=l;i--)

typedef long long ll;

using namespace std;

inline ll _max(const ll& a,const ll& b){return a>b?a:b;}
inline ll _min(const ll& a,const ll& b){return a<b?a:b;}
inline ll _abs(const ll& a){return a>0?a:-a;}

ll n,N;
ll r;

ll solve(ll l,ll r,ll R){
    //cout<<"计算"<<l<<","<<r<<"的总和"<<endl;
    ll sum = 0;

    ll lh,rh;
    lh = l/R;//左侧的阶梯状高度
    rh = r/R;//右侧的阶梯状高度
    if(lh == rh){
        sum = (r-l+1)*lh;
    }
    else{
        ll lleft = (l/R+1)*R - l;
        ll rleft = r%R+1;
        ll num = (r/R) - (l/R+1);
        //printf("在区间[%d,%d]左侧剩余%d,右侧剩余%d,中间有%d\n",l,r,lleft,rleft,num);
        sum = R*num*(lh+1+rh-1)/2 + lleft*lh + rleft*rh;
    }
    //cout<<"为"<<sum<<endl;
    return sum;
}

int main()
{
    cin>>n>>N; 
    r = N/(n+1);
    ll ans = 0;
    ll a,lpos = 0;
    up(1,n+1,i){
        if(i != n+1)
            cin>>a;
        else
            a = N;
        a--;
        ll lh,rh;
        lh = lpos/r;//左侧的阶梯状高度
        rh = a/r;//右侧的阶梯状高度

        if((i-1-lh)*(i-1-rh) >= 0){
            //printf("与之对应的%d\n",(i-1)*(a-lpos+1));
            ans += _abs((i-1)*(a-lpos+1) - solve(lpos,a,r));
        }
        else{
            ll mid = (i-1)*r;
            //cout<<"选出中点为"<<mid<<endl;
            ans += _abs((i-1)*(mid-lpos+1) - solve(lpos,mid,r));
            ans += _abs((i-1)*(a-mid) - solve(mid+1,a,r));
        }

        lpos = a+1;

    }
    //printf("与之对应的%d\n",(N-lpos)*n);
    //ans += _abs((N-lpos)*n - solve(lpos,N-1,r));

    cout<<ans<<endl;


    return 0;
}
View Code

 

posted @ 2024-04-07 16:14  dudujerry  阅读(41)  评论(0编辑  收藏  举报