CCF CSP 202112-1题(两种方法AC)

CCF CSP 202112-1题

题目背景

image-20220311215158102

题目描述

image-20220311215240720

输入格式

image-20220311215302213

输出格式

image-20220311215332501

样例1输入

3 10
2 5 8

样例1输出

15

样例1解释

image-20220311215453724

样例2输入

9 10
1 2 3 4 5 6 7 8 9

样例2输出

45

子任务

image-20220311215552768

提示

image-20220311215611283

题目分析

  1. 题目中的A序列,可以分析得到,An>=n

  2. f(x)有两种情况

    a> 0<=i<n && Ai<=x<Ai+1 时f(x)=i;

    b> n<=An<=x 时f(x)=n;

  3. 求的是sum(A) 也就是f(0)+f(1)+f(2)+……+f(N-1)

  4. 序列A必定是从0开始(不大于0的数字只能是0),也就是说f(i)也会是从0开始依次递增,因为后面i的数字变大,然后不大于1,不大于2,不大于3,不大于4才逐渐会变化f(i)为A序列第二个数字,第三个数字。

根据题目样例解释进行解析

image-20220311221901785

根据以上的规律,可以得出,情况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;
} 

方法二(网上查到的)

思路解析

前缀和+差分

image-20220311225123944

  1. f(x)=diff(1)+diff(2)+diff(3)+……+diff(x)=f(x)-f(0)

  2. 当i逐1递增到序列A下一个数字时,说明f(x)的值后续都需要加一(因为下标会向后移动)

  3. 此时我们就对diff(A[i])++;这样子后续加起来的时候后续所有的f(x)都会加上这个1了

    image-20220311230052723

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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值