202112-2 序列查询新解

70分题解

先说一个70分的解法,因为我想的是我这个解法虽然是o(n),但是其实也用了一些巧妙的思路。
这个想法只需要一个for循环,但问题是N-1~0的for循环。
xia代表c数组某个值对应的下标。

#include <iostream>
using namespace std;
#include <bits/stdc++.h>
#include<algorithm>
int c[100010];
int main()
{
    int n,m;
    cin>>n>>m;
    int r=m/(n+1);
    long long int sum=0;
    for(int i=1;i<=n;i++)cin>>c[i];
    int xia=n,zhi=c[xia--];//用来存储下标,也就是f(i)
    for(int i=m-1;i>=0;i--)
    {
        int f,g;
        //c【n】小于等于i,表明这时的f(i)等于n
        if(zhi<=i)f=xia+1;//因为前面用了xia--,所以要加回来
        else{
        //c【n】大于i,表明c【i】的值该减小了
            zhi=c[xia--];
            f=xia+1;
        }
        g=i/r;
        sum+=abs(g-f);
    }
    cout<<sum;
    return 0;
}

100分题解

70分题解超时的原因是我们的N太大了,因此即使是O(n)也依旧会超时,因此我们就要想如何才能让for循环的次数减少。第一题202112-1 序列查询提示了我们要进行分段查询,因此我们可以考虑如何进行分段,通过分析可以发现c[i]~c[i+1]-1区间的f值是相等的,于是咱首先想到的是将f先进行分段。其次,我们会发现如果这样分段,某一个分段区间的g值会不相同,但是仔细分析后会发现,g值的范围咱是可以知道的,在f值分段为c[i] ~c[i+1]-1的区间中,g的范围是c[i]/r ~(c[i+1]-1)/r。因此咱们又可以将此区间的g分为r的小的区间。
代码如下:
le用来记录每次计算后当前值的大小(这个值是相对于N来说的),以便用来计算在该r区间的个数。

#include <iostream>
using namespace std;
#include <bits/stdc++.h>
#include<algorithm>
int c[100005];
int main()
{
    int n,m;
    cin>>n>>m;
    long long int sum=0;
    for(int i=1;i<=n;i++)cin>>c[i];
    c[++n]=m;
    int r=m/n;
    for(int i=0;i<=n-1;i++)//分为n个段,同时i还代表了f在此区间的取值
    {
        int le=c[i],ri=c[i+1];//le记录左值,ri记录右值
        for(int j=le/r;j<=(ri-1)/r;j++)//j代表g在这个区间可能的取值范围
        {
            if((j+1)*r>ri)sum=sum+(ri-le)*abs(j-i);
            else sum=sum+((j+1)*r-le)*abs(j-i);//当前一个r的区间中的个数*差值的绝对值
            le=(j+1)*r;
        }
    }
    cout<<sum;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值