CSP 202112-1 序列查询(前缀和+差分)


首先,我们来理一遍题意,第一行输入n是整数序列长度,且整数值小于N,第二行为整数序列A1~An,f(x)是序列中小于等于x的整数里最大的数的下标。我们需要计算的是sum=f(0)+f(1)+...+f(N-1)。

本来没什么思路,但一看到样例解释,这不就是前缀和+差分嘛!

用样例1来解释一下思路:

思路:根据题意,当x<2时,序列中小于等于x的最大数是0,下标为0,即f(0),f(1)都为0,当2<=x<5时,序列中小于等于x的最大数是2,下标为1,即f(2)~f(4)都为1,则可知当x取[A[i],A[i+1])时,序列中小于等于x的最大数是A[i],下标为i,即f(A[i])~f(A[i+1]-1)都等于i。

因为f(x)某一段范围内的值都相等,且每一段范围内f(x)的值比前一段范围内的都要大1。所以我们可以让f(x)在范围[A[1],N-1]的值为1,后面每段范围的值在原基础上+1,即每段范围[A[i],N-1]的值++,由此想到可以用差分和前缀和的方法。

开始解题:我们设置一个差分数组dif,dif[i]表示的是f(i)-f(i-1),现在要使下标为[2,9]的f(x)值都要+1,那么对于下标为[2,9]的元素来说,它们的差分不会改变,因为大家都加了1,所以对一个范围内的值操作,影响的只是范围内与范围外的值的差分,即范围的临界的差分。所以dif[2]++即可。同理,我们要使下标为[5,9]的f(x)值都要+1,dif[5]++即可。所以最后,我们只做了dif[2]++,dif[5]++,dif[8]++的工作,从而求出了f(x)的差分数组。

根据定理:f(x)=dif[1]+dif[2]+...+dif[x]=f(x)-f(0),最后再求f(x)的和即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int M=1e7+5;
int n,N,dif[M],f[M];
int main(){
    int a;
    cin>>n>>N;
    for(int i=1;i<=n;i++){
        cin>>a;
        dif[a]++;
    }
    int res=0;
    for(int i=1;i<N;i++)
       { f[i]=f[i-1]+dif[i]; res+=f[i];}
    cout<<res;
    return 0;
}

思路来源于:https://www.cnblogs.com/yongcheng137blogs/p/15412952.html

202109-2 非零段划分也是这个方法


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM