202112-2 序列查询新解

202112-2 序列查询新解

题目描述

题目分析

我以第一个输入举例,第一次用二分查找可以找出f[x]对应的值g[x] = x / r ,所以依题意可以很容易写出来。

x 0 1   2 3 4    5 6 7  8 9
A 0     2        5      8   10
i 0     1        2      3    
fx0 0   1 1 1    2 2 2  3 3
gx0 0   1 1 2    2 3 3  4 4

二分模板

void erfen1()
{
    while (l < r)
    {
        int mid = l + r >> 1;	//(l+r)/2
        if (check(mid))  r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }

}

void erfen2()
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;	//(l+r+1)/2
        if (check(mid))  l = mid;
        else r = mid - 1;
    }

}
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std ;
const int M = 10010;
int n , N ;
int A[M] , f[M] , g[M];

int ff(int x)
{
    int l = 0 , r = n  ;
    while ( l < r)
    {
        int mid = (l + r + 1) >> 1 ;
        if (A[mid] <= x){
            l = mid ;
        } else{
            r = mid - 1 ;
        }
    }
    return l ;
}
int main()

{
    cin >> n >> N ;
    A[0] = 0 ;

    for (int i = 1 ; i <= n ; ++i)
    {
        cin >> A[i] ;
    }

    int res = 0 ;
    int r = N / (n + 1) ;
    for (int i = 0 ; i < N ; ++i)
    {
        f[i] = ff(i) ;
        g[i] = i / r ;
        res += abs(g[i] - f[i]) ;
    }

    // int res = 0 ;
    // for (int i = 0 ; i < N ; ++i)
    // {
    //     res += abs(g[i] - f[i]) ;
    // }
    cout << res  ;
    return 0 ; 
    
}

题目分析

上述答案为70分,通过分析可以知道,二分的时间复杂度为O(nlogn),0<=N<=1e9,如果按照O(N * nlogn),1<=n<=1e5,因此遍历条件不能为N,我们选择用n来遍历,也就是选择点。

x 0 1   2 3 4    5 6 7  8 9
A 0     2        5      8   10
i 0     1        2      3    
fx0 0   1 1 1    2 2 2  3 3
gx0 0   1 1 2    2 3 3  4 4

通过上述样例分析出,当r = N / (n + 1) = 2时,fx和gx都按照一定的规律进行变化,并且我们在遍历点的时候,fx=i,gx在A[i]-A[i+1]-1中变化,for (ll j = A[i] ; j <= A[i+1] - 1; j += dr ),gx = j / r ;值得我们注意的是,当区间不足r时,fx和gx的值是不一样的,并且影响了最后一段和下一段的开始,我们用r和A[i+1]来进行判断,如果j+r -1 > A[i+1] - 1,也就是j + dr > A[i+1],说明在当前区间最后一段只有小于r的一个区间,那么我只需要加上A[i+1] - j的长度* res,完成此操作后,还要对下一段的开始进行操作,也就是dr-(A[i+1] - j),在操作完之后,下一个区间的增加长度又为r了。

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std ;

typedef long long ll ;

const int nn = 100010 ;
ll A[nn] , f , g;
int N , n;

int main()

{
    cin >> n >> N ;
    A[0] = 0 ;

    for (int i = 1 ; i <= n ; ++i)
    {
        cin >> A[i] ;
    }

    A[n + 1] = N ;
    ll r = N / (n + 1) ;
    int dr = r ;
    ll error = 0;
    int ddr ;
    int flag =  0;
    for (int i = 0 ; i < n + 1; ++i)
    {
        f = i ;
        // cout << f << endl ;
        for (ll j = A[i] ; j <= A[i+1] - 1; j += dr )
        {
            // cout << j << "->" << A[i+1] - 1 << endl;
            g = j / r ;
            ll res = f > g ? f-g : g-f ;
            // cout << sum << endl ;
            if (flag == 1)
            {
                dr = ddr ;
                flag = 0 ;
            } else {
                dr = r ;
            }

            if (j + dr<= A[i+1]) {
                error += (res * dr) ;
            }
            if (j + dr > A[i+1] ){
                error += (A[i+1] - j) * res ;
                ddr = dr - (A[i+1] - j) ;
                flag = 1 ;
            }
        }
    }
    cout << error <<endl;
    return 0 ;
}

总结

题目不难,但是自己还是只写出了70分的答案,刚开始想的用离散化,但还是会用二分,本质上没有区别,最后,提醒一下自己一定要认真审题!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值