洛谷 P4983 忘情

PS:如果读过题了可以跳过题目描述直接到题解部分
提交链接:洛谷 P4983 忘情

题目

题目背景

“为什么要离开我!”

“因为你没玩儿转!”

“我玩儿转了!”

“那好,你现在就给我维护这么一个式子!”

“为什么要出这么毒瘤的东西。”

“为了恶心你。”

“…”

… … … … … … … … … … … . ……………………………. …………………………….

题目描述

你的 n p y npy npy 为了恶心你,特地请了四位大神和一个辣鸡!

h d x r i e \rm hdxrie hdxrie 说:“我们得求和。”于是有了 Σ i = 1 n x i \Sigma_{i=1}^{n}x_i Σi=1nxi

I m a g i n e \rm Imagine Imagine 说:“我们得有平均数。”于是有了 x ˉ \bar x xˉ

T i m e T r a v e l l e r \rm TimeTraveller TimeTraveller 说:“我们得有加减乘除。”于是有了一些恶心的组合。

A l t h e n ⋅ W a y ⋅ S a t a n \rm Althen·Way·Satan AlthenWaySatan 说:“我们还得有平方。”于是我们将它平方。

最垃圾的 Z r e d X N y \rm ZredXNy ZredXNy 说:“那我帮你们整合一下。”

于是,我们得到了这么一个式子 : : :

( ( Σ i = 1 n x i × x ˉ ) + x ˉ ) 2 x ˉ 2 \frac{\left((\Sigma_{i=1}^{n}x_i×\bar x)+\bar x\right)^2}{\bar x^2} xˉ2((Σi=1nxi×xˉ)+xˉ)2

我们定义一段序列的值为这个,其中 n n n为此序列的元素个数。

我们给定一段长度为 n n n 的序列,现在要求将它分成 m m m 段,要求每一段的值的总和最小,求出这个最小值。

输入格式

第一行两个正整数,分别为 n n n m m m,定义见题面。

接下来一行为 n n n 个正整数,依次给出这个序列的每个元素的值 x i x_i xi

输出格式

一个整数,求出这个最小值。

样例 #1

样例输入 #1

3 2
1 2 3

样例输出 #1

32

样例 #2

样例输入 #2

10 3
1 2 3 4 5 6 7 8 9 10

样例输出 #2

1140

提示

  • 对于 30 % 30 \% 30% 的数据, m ≤ n ≤ 500 m≤n≤500 mn500

  • 另有 20 % 20 \% 20% 的数据,保证 m = 2 m=2 m=2

  • 对于 100 % 100 \% 100% 的数据, m ≤ n ≤ 100000 m≤n≤100000 mn100000 1 ≤ x i ≤ 1000 1≤x_i≤1000 1xi1000

题解

我们先来化简一下这道题要求的东西:
( ( Σ i = 1 n x i × x ˉ ) + x ˉ ) 2 x ˉ 2 \frac{\left((\Sigma_{i=1}^{n}x_i×\bar x)+\bar x\right)^2}{\bar x^2} xˉ2((Σi=1nxi×xˉ)+xˉ)2
= ( ( Σ i = 1 n x i ) 2 n + Σ i = 1 n x i n ) 2 ( Σ i = 1 n x i n ) 2 =\frac{(\frac{(\Sigma_{i=1}^{n}x_i)^2}{n}+\frac{\Sigma_{i=1}^{n}x_i}{n})^2}{(\frac{\Sigma_{i=1}^{n}x_i}{n})^2} =(nΣi=1nxi)2(n(Σi=1nxi)2+nΣi=1nxi)2
= ( Σ i = 1 n x i n ) 2 × ( 1 + Σ i = 1 n x i n ) 2 ( Σ i = 1 n x i n ) 2 =\frac{(\frac{\Sigma_{i=1}^{n}x_i}{n})^2\times(1+\frac{\Sigma_{i=1}^{n}x_i}{n})^2}{(\frac{\Sigma_{i=1}^{n}x_i}{n})^2} =(nΣi=1nxi)2(nΣi=1nxi)2×(1+nΣi=1nxi)2
= ( 1 + Σ i = 1 n x i n ) 2 =(1+\frac{\Sigma_{i=1}^{n}x_i}{n})^2 =(1+nΣi=1nxi)2
为了方便接下来的表示,我们令 S i S_i Si表示序列第 i i i段中所有元素的和。
原式 = ( 1 + S 1 ) 2 + ( 1 + S 2 ) 2 + . . . + ( 1 + S m ) 2 原式=(1+S_1)^2+(1+S_2)^2+...+(1+S_m)^2 原式=(1+S1)2+(1+S2)2+...+(1+Sm)2
= 1 + 2 × S 1 + S 1 2 + 1 + 2 × S 2 + S 2 2 + . . . + 1 + 2 × S m + S m 2 =1+2\times S_1+S_1^2+1+2\times S_2+S_2^2+...+1+2\times S_m+S_m^2 =1+2×S1+S12+1+2×S2+S22+...+1+2×Sm+Sm2
= m + 2 × Σ i = 1 n x i + Σ i = 1 m S i =m+2\times \Sigma_{i=1}^nx_i+\Sigma_{i=1}^mS_i =m+2×Σi=1nxi+Σi=1mSi
显然当序列一定的时候可以分成的段数越多,值的总和越小,所以题目中的m给了多大,我们就要每一段都分掉,而不会有空段。

20pts

我考试的时候,还不太写得来斜率优化,于是就写的dfs,严重超时。

100pts

它每分一段的时候原本是没有任何代价的,所以分的段数越多,就一定越优。而题目中有对段数的限定,这是十分不好处理的,所以我们换一个限定方式。

假设在它每分一段的时候都有了一个代价,那么我们会发现,代价增加的同时,最优的段数会逐渐减少,所以我们只需要二分这个代价的大小,直到它的最优段数等于我们在题目中限定的段数的时候,用我们求到的答案减去代价与段数的乘积(也就是总代价)就是我们最后要求的答案了。

代码实现

20pts

//洛谷 P4983 忘情
#pragma GCC optimize(3)
#include<cstdio>
#include<iostream>
using namespace std;
long long n,m;
long long x[100010];
long long s[100010];
long long ans;
int a[100010];

void re(long long &x){
	int nt;
	x=0;
	while(!isdigit(nt=getchar()));
	x=nt^'0';
	while(isdigit(nt=getchar())){
		x=(x<<3)+(x<<1)+(nt^'0');
	}
}

long long dfs(int i,int j){
	a[j]=i;
	long long ans=0;
	if(j==m-1){
		for(i=1;i<=m;++i){
			ans+=1ll*(s[a[i]]-s[a[i-1]])*(s[a[i]]-s[a[i-1]]);
		}
		return ans;
	}
	int k=i+1;
	while(s[k]-s[i]<(s[n]/m)&&n-k>=j){
		++k;
	}
	ans=min(dfs(k+1,j+1),min(dfs(k-1,j+1),dfs(k,j+1)));
	return ans;
}

int main(){
	register int i;
	re(n),re(m);
	for(i=1;i<=n;++i){
		re(x[i]);
		s[i]=s[i-1]+x[i];
	}
	a[m]=n;
	ans=dfs(0,0)+m+2ll*s[n];
	printf("%lld\n",ans);
	return 0;
}

100pts

//洛谷 P4983 忘情
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const long long inf=1e18;
long long n,m;
long long x[100010];
long long s[100010];
long long ans;
long long f[100010];
long long g[100010];
long long q[100010];

void re(long long &x){
	int nt;
	x=0;
	while(!isdigit(nt=getchar()));
	x=nt^'0';
	while(isdigit(nt=getchar())){
		x=(x<<3)+(x<<1)+(nt^'0');
	}
}

void check(long long mid){
	memset(f,0x3f,sizeof(f));
	memset(g,0,sizeof(g));
	f[0]=0;
	int l=1,r=1;
	q[1]=0;
	for(int i=1;i<=n;++i){
		while(l<r&&((long double)(f[q[l+1]]+s[q[l+1]]*s[q[l+1]]-2*s[q[l+1]]-f[q[l]]-s[q[l]]*s[q[l]]+2*s[q[l]]*1.0)/(s[q[l+1]]-s[q[l]])<2*s[i])){
			++l;
		}
		f[i]=f[q[l]]+(s[i]-s[q[l]]+1)*(s[i]-s[q[l]]+1)+mid;
		g[i]=g[q[l]]+1;
		while(l<r&&(long double)(f[q[r]]+s[q[r]]*s[q[r]]-2*s[q[r]]-f[q[r-1]]-s[q[r-1]]*s[q[r-1]]+2*s[q[r-1]])*1.0/(s[q[r]]-s[q[r-1]])>(long double)(f[i]+s[i]*s[i]-2*s[i]-f[q[r-1]]-s[q[r-1]]*s[q[r-1]]+2*s[q[r-1]])/(s[i]-s[q[r-1]])){
			--r;
		}
		q[++r]=i;
	}
}

int main(){
	register int i;
	re(n),re(m);
	for(i=1;i<=n;++i){
		re(x[i]);
		s[i]=s[i-1]+x[i];
	}
	long long l,r,mid;
	l=0,r=inf,ans=0;
	while(l<=r){
		long long mid=l+r>>1;
		check(mid);
		if(g[n]<=m){
			ans=mid;
			r=mid-1;
		}
		else{
			l=mid+1;
		}
	}
	check(ans);
	printf("%lld\n",f[n]-m*ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月半流苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值