CCF 202112-2 序列查询新解(C++)

image

该题关键点在于:分段计算

  1. 先对f分段:for(int i=1;i<=n+1;i++) //以 f(i) 为区域划分计算 在此区域内f的取值相同,值为:i-1。
  2. 再对每个f值相同的区域按照g值进行分段:for(int j=a[i-1];j<=a[i]-1;j=j+Long){//此区间内有Long个g取值为g(j)的数
  3. j 值改变条件为:j=j+Long,这个Long为变值,因为g取值相同的区间不完全与 f 取值相同的区间对齐。
    所以每次都要计算此Long:Long=NumLong=NumEnd-j+1;
    注:由于此特性,所以g取值的上界可能超出了此区间(按f取值相同来划分的区间)的上界
    所以需要此语句:if(NumEnd>a[i]-1) NumEnd=a[i]-1;//上界超出范围,变为区间最上界 ,来将此情况的bug修复。
#include<iostream>
#include<bits/stdc++.h>

using namespace std;

#define num 100002

int n = 0;
int N = 0;
int a[num]={0};
int r = 0;
int Long = 0;
long long sum = 0;

void input()
{   // 输入
    cin >> n >> N;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
    }
}

long long g(int x)
{   // 计算g(x)的值
    return x/r;
}

int main()
{
    input();
    r=N/(n+1);
    a[n+1]=N;
    a[0]=0;
    // Long = r;
    for(int i = 1; i <= n+1; i++){//以f(i)为区域划分计算
        long long sum1 = 0;//记录此小区间差值的和
        for (int j = a[i-1]; j <= a[i]-1; j = j+Long){
            int NumEnd=(g(j)+1)*r-1;
            if (NumEnd>a[i]-1) NumEnd=a[i]-1;
            int NumLong = NumEnd-j+1;
            long long f_g = abs(i-1-g(j));
            sum1 = sum1+f_g*NumLong;
            Long = NumLong;
        }
        sum += sum1;
    }

    cout << sum << endl;
    return 0;
}

posted @ 2022-08-27 11:10  白缺  阅读(353)  评论(0编辑  收藏  举报