IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【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(i)的数为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值皆恒定,即两者的差值也恒定:以差值乘以数量即可,最后将所有区间计算量加起来即可。

3、提交结果

请添加图片描述

三、其他思路

再附上一个代码,案例能对,但是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;
} 

四、题目如下:

请添加图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 13:22:01  更:2022-03-06 13:23:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 9:23:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码