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;
}