【csp202112-2】序列查询新解

题目在这里

第一次写的时候直接做的,70分运行超时,最近几次的第二题都是这个套路,坏的很

仔细看样例解释会发现有很多重复的值,是否说明,我们不需要重复算呢?

对于a[i]和a[i-1]之间的x,它们的f(x)都是i-1

对于kr和(k-1)r之间的x,它们的g(x)都是(k-1)

对于两者区间交叉中的差值恒定,区间中整数的个数*差值即可

接下来的难点就是如何获得区间中整数的个数。

基于我说的两条规则,可以画出六种f(x)和g(x)值不变时区间的关系。

N最大为10^9,遍历N就是我第一次写的时候,超时了,那我们只能遍历数组a,移动N的x区间

根据上面6种关系,其中处理方法可以分为两大类。

如果a[i]>kr,那就后移kr直到kr>=a[i]

如果a[i]<=kr,那就继续

代码上有详细注释,建议6种区间关系自己画图看看,很清楚的。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long get_result(){
    long long n,N;
    cin>>n>>N;
    int r=N/(n+1);
    long long a[n+2];
    //对于a[i]和a[i-1]之间的x,它们的f(x)都是i-1
    //对于kr和(k-1)r之间的x,它们的g(x)都是(k-1)
    //对于两者区间交叉中的差值恒定,区间中整数的个数*差值即可
    long g_x=0;//(k-1)r
    long next_x=r;//kr
    long now_x=0;//(k-1)r
    long long s=0;//结果
    a[0]=0;
    for(long i=1;i<=n;++i){
        cin>>a[i];
    }
    a[n+1]=N;
    for(long i=1;i<=n+1;++i){
        //根据两者区间的位置不同,一共六种可能,总结有两大类处理方法
        if(next_x>=N){
            next_x=N;
        }
        while(next_x<a[i]){//如果a[i]较大,g_x+=1,next_x+=r
            if(a[i-1]<next_x){//如果两者区间相交,则需要计算相交区域的值
                int l=min(int(next_x-a[i-1]),int(next_x-now_x));//取小的那个为区间大小
                s+=abs((long long)l*(g_x-(i-1)));
            }
            //往后挪一位
            g_x+=1;
            next_x+=r;
            now_x+=r;
            if(now_x>=N){
                return s;
            }
        }
        //此时一定是next_x较大,这时直接算
        //这种情况下有三种可能
        if(g_x<a[i]){//如果两者区域相交,则需要计算相交区的值
            int l=min(int(a[i]-a[i-1]),int(a[i]-now_x));//取小的那个为区间大小
            s+=abs((long long)l*(g_x-(i-1)));
        }
    }
    return s;
}
int main(){
    cout<<get_result()<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值