【CCF-CSP】202112-2-序列查询新解100分(读过必懂)

简介: 【CCF-CSP】202112-2-序列查询新解100分(读过必懂)

一、🌳代码如下:

#include <iostream>
#include <cmath> //绝对值函数abs()头文件
using namespace std;
#define num 100002

int n=0;//序列有n个数 
int N=0;//N的值 
int a[num]={0};//序列最多有1*10^5个数 
int  r=0;// r=N/(n+1) 
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);    //cout<<r<<endl; //检验r的计算 
    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){//此区间内有Long个g取值为g(j)的数 
            int NumEnd=(g(j)+1)*r-1;//g取值为g(j)最大的数为NumEnd
            if(NumEnd>a[i]-1) NumEnd=a[i]-1;//上界超出范围,变为区间最上界 
            int NumLong=NumEnd-j+1;//取值为g(j)的数为NumLong个
            long long f_g=abs(i-1-g(j));//f与g差值,f值恒为i-1 
            sum1=sum1+f_g*NumLong;
            Long=NumLong;
        }
        sum=sum+sum1;            
    }
    
    cout<<sum<<endl;
    return 0;
} 

二、🌵解题思路

1、观察性质🍠

f(x)定义:序列A中小于等于x的整数里的最大的数的下标。
g(x)计算方式:r=N/(n+1)   g(x)=x/r
可得f(x)、g(x)分布皆为公差为1的递增序列
示例给的图很直观的表现了此规律:
请添加图片描述

2、求解步骤🍅

(1)、题目的暗示

CSP的第一、二题联系紧密,这次的第一题中已经给出了暗示:分段!
如果忘了第一题讲是什么?可以看我的这篇文章:【CCF-CSP】202112-1-序列查询100分
其中详细分析了题意、解题思路并附上了题目截图。

(2)、如何分段

🍀先对f分段:for(int i=1;i<=n+1;i++) //以f(i)为区域划分计算
在此区域内f的取值相同,值为:i-1
🌍再对每个f值相同的区域按照g值进行分段:for(int j=a[i-1];j<=a[i]-1;j=j+Long){//此区间内有Long个g取值为g(j)的数
🔥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修复。

(3)、求和

上述操作先按f取值相同分段,再按g值相同分段,所以在最底层的段中f值与g值皆恒定,即两者的差值也恒定:以差值乘以数量即可,最后将所有区间计算量加起来即可。

三、其他思路

再附上一个代码,案例能对,但是0分,数据太大爆了,有兴趣的可以看看思路。
#include <iostream>

using namespace std;
#define num 100002

int n=0;//序列有n个数 
int N=0;//N的值 
int long a[num]={0};//序列最多有1*10^5个数 
int long r=0;// r=N/(n+1) 
long long sum=0;

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

void output(){//输入,检验输入是否正确 
    cout<<n<<" "<<N<<endl;
    a[0]=0;
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }    
    cout<<endl;
} 


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

long long    GSum(long long x,long long  y){//求x到y间,g(i)的和 
    long long gsum=0;
    if(g(x)==g(y)){
        gsum=g(x)*(y-x+1);//相同的g()值共y-x+1个 
    }
    else{
        long long xTop=(x%r)*g(x);//此区间内不包括前(x%r)个g(x) 
        long long yTop=(y%r+1)*g(y);//此区间内包含(y%r+1)个g(y);
        //r组相同的等差数列,首项为g(x),末项为g(y)-1,共 g(y)-1-g(x)+1项 
        gsum=r*((g(x)+g(y)-1)/2*(g(y)-1-g(x)+1)); 
        gsum=gsum-xTop+yTop;//修正sum,多加的xTop需减去,少加的yTop需加上    
    }
    return gsum; 
}


int main(){
    input();
    r=N/(n+1);    //cout<<r<<endl; //检验r的计算 
    a[n+1]=N;
    for(int i=1;i<=n+1;i++){//以f(i)为区域划分计算 
        
        long long fFlag=i-1;//记录此区间的f(i)值 
        long long LeftFlag=a[i-1]; //区间左边界 
        long long RightFlag=a[i]-1;//区间右边界 
        long long LongFlag=RightFlag-LeftFlag+1;//区间长度 
        //i在LeftFlag与RightFlag中,f(i)取值相同
        
        if(LongFlag==1){//区间仅一个长度 
            long long m1=fFlag-g(LeftFlag);
            if(m1<0) m1=(-1)*m1;
            sum=sum+m1;
        } 
        else if(g(LeftFlag)>=fFlag){//在此区间内,g(i)恒大于等于f(i),f(i)恒=i-1 
            sum=sum+GSum(LeftFlag,RightFlag)-fFlag*LongFlag;
        }
        else if(g(RightFlag)<=fFlag){//在此区间内,g(i)恒小于等于f(i),f(i)恒=i-1 
            sum=sum+fFlag*LongFlag-GSum(LeftFlag,RightFlag);
        } 
        else{//在此区间内,g(i)先<=f(i),后>f(i) 
            int WhereFlag=0;//记录g(i)>f(i)的左临界
            for(int j=LeftFlag;j<=RightFlag;j++){
                if(g(j)>fFlag){
                    WhereFlag=j;
                    break;//跳出 
                }
            }
            long long LeftLong=WhereFlag-LeftFlag;//g(i)<=f(i)部分长度 
            long long RightLong=RightFlag-WhereFlag+1;//g(i)>f(i)部分长度 
            long long sum1=fFlag*LeftLong-GSum(LeftFlag,WhereFlag-1);
            long long sum2= GSum(WhereFlag,RightFlag)-fFlag*RightLong;
            sum=sum+sum1+sum2; 
        }
        //cout<<sum<<endl;
    }
    cout<<sum<<endl;
    return 0;
} 
目录
相关文章
|
Go Python
CSP 202112-1 序列查询 python
CSP 202112-1 序列查询 python
CSP 202112-1 序列查询 python
|
人工智能 Go Python
CSP 202112-2 序列查询新解 python 离散+二分法
CSP 202112-2 序列查询新解 python 离散+二分法
CSP 202112-2 序列查询新解 python 离散+二分法
|
测试技术 Go Python
CSP 202009-1 称检测点查询 python
CSP 202009-1 称检测点查询 python
CSP 202009-1 称检测点查询 python
|
Go C++
CSP 202112-2 序列查询新解
CSP 202112-2 序列查询新解
141 0
CSP 202112-2 序列查询新解
|
Go C++
CSP 202112-1 序列查询
CSP 202112-1 序列查询
86 0
CSP 202112-1 序列查询
|
人工智能 算法
【CCF-CSP】202112-1-序列查询100分
【CCF-CSP】202112-1-序列查询100分
322 0
【CCF-CSP】202112-1-序列查询100分
第五十二章 开发自定义标签 - Using csr %CSP.AbstractAtom Write Methods
第五十二章 开发自定义标签 - Using csr %CSP.AbstractAtom Write Methods
73 0
|
JavaScript 编译器 Go
第五十一章 开发自定义标签 - 使用%CSP.Rule方法
第五十一章 开发自定义标签 - 使用%CSP.Rule方法
82 0
|
SQL JavaScript 前端开发
第三十六章 使用 CSP 进行基于标签的开发 - 使用尽可能少的#server和#call调用
第三十六章 使用 CSP 进行基于标签的开发 - 使用尽可能少的#server和#call调用
131 0
|
JavaScript 前端开发 Go
第三十四章 使用 CSP 进行基于标签的开发 - Hyperevent例子
第三十四章 使用 CSP 进行基于标签的开发 - Hyperevent例子
120 0