CCF CSP 202112-1题
文章目录
题目背景

题目描述

输入格式

输出格式

样例1输入
3 10
2 5 8
样例1输出
15
样例1解释

样例2输入
9 10
1 2 3 4 5 6 7 8 9
样例2输出
45
子任务

提示

题目分析
-  题目中的A序列,可以分析得到,An>=n 
-  f(x)有两种情况 a> 0<=i<n && Ai<=x<Ai+1 时f(x)=i; b> n<=An<=x 时f(x)=n; 
-  求的是sum(A) 也就是f(0)+f(1)+f(2)+……+f(N-1) 
-  序列A必定是从0开始(不大于0的数字只能是0),也就是说f(i)也会是从0开始依次递增,因为后面i的数字变大,然后不大于1,不大于2,不大于3,不大于4才逐渐会变化f(i)为A序列第二个数字,第三个数字。 
根据题目样例解释进行解析

根据以上的规律,可以得出,情况a的时候,由于i会逐1增加,所以在没超过序列A中下一个数时,其f(i)都会保持不变,这里也与题目的提示相应和,所以A序列中的数字差,就是下面f(i)中每区段内相同数字的个数,i(下标)就是下方f(i)的区段内的f(i),在情况b的时候,可以猜想出,随着i的增加,f(i)的值已经超过最大的下标n,所以就只能全部为n,也就是说,从n到N也可以作为一个区段,这时的i全部大于An,下标也对应为最后一个i,一直到N,个数也可以通过N-n也就是数字差来计算,所以将N合并到A序列中,如此,我们统一了计算过程
也就是说我们也可以根据题目的计算得出公式
sum(A) = f(0) x 2 + f(2) x 3 + f(5) x 3 +f(8) x 2
= 0 x (2-0) + 1 x (5-2) + 2 x (8-5) +3 x (10-8)
最后得到
sum += (A[i]-A[i-1]) * (i-1)
AC Code
#include <iostream>
using namespace std;
int main(){
	int n, N;
	scanf("%d %d",&n,&N); 
	int A[n+2];
	A[0]=0;
	A[n+1]=N;
	// 一个A[0]=0 一个A[n+1]=N 都是为了计算添加的 
	for(int i=1;i<=n;i++){
		cin>>A[i]; 
	}
	int sum=0;
	for(int i=1;i<=n+1;i++){
		sum+=(A[i]-A[i-1])*(i-1);
	}	
	printf("%d",sum);
	return 0;
} 
方法二(网上查到的)
思路解析

-  f(x)=diff(1)+diff(2)+diff(3)+……+diff(x)=f(x)-f(0) 
-  当i逐1递增到序列A下一个数字时,说明f(x)的值后续都需要加一(因为下标会向后移动) 
-  此时我们就对diff(A[i])++;这样子后续加起来的时候后续所有的f(x)都会加上这个1了  
AC Code
#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]++;
        //差分数组,无论操作多少次,最后f(x)求和的时候都只计算一次
    }
    int res=0;
    for(int i=1;i<N;i++){ 
        //求得f(i)的方法
        f[i]=f[i-1]+dif[i];
        //将此f(i)加入和
        res+=f[i];
    }
    cout<<res;
    return 0;
}










