洛谷 P2669 金币(纯数学解法)

原题

题目背景

NOIP2015 普及组 T1

题目描述

国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币……;这种工资发放模式会一直这样延续下去:当连续 n n n 天每天收到 n n n 枚金币后,骑士会在之后的连续 n + 1 n+1 n+1 天里,每天收到 n + 1 n+1 n+1 枚金币。

请计算在前 k k k 天里,骑士一共获得了多少金币。

输入格式

一个正整数 k k k,表示发放金币的天数。

输出格式

一个正整数,即骑士收到的金币数。

输入输出样例

输入 #1
6
输出 #1
14
输入 #2
1000
输出 #2
29820

说明/提示

【样例 1 说明】

骑士第一天收到一枚金币;第二天和第三天,每天收到两枚金币;第四、五、六天,每天收到三枚金币。因此一共收到 1 + 2 + 2 + 3 + 3 + 3 = 14 1+2+2+3+3+3=14 1+2+2+3+3+3=14枚金币。

对于 100 % 100\% 100%的数据, 1 ≤ k ≤ 1 0 4 1≤k≤10^4 1k104

开始解题

一.双重循环解法

很简单,上代码。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,cnt=0,sum=0;
	cin>>n;
	for(int i=1;;i++){
		for(int j=1;j<=i;j++){
			sum+=i;
			cnt++;
			if(cnt==n){
				cout<<sum;
				return 0;
			}
		}
	}
}

想必这个各位是轻轻松松就能看得懂的,我就不过多赘述了

二.单循环解法

而这个单循环的解法在本质上跟上面哪一个双循环的时间复杂度一样
都是 O ( n ) O(n) O(n)
(所以只是看上去顺眼了一点)
依然不多说,上代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,a=1,sum=0,i=1;
	cin>>n;
	for(int j=1;j<=n;j++){
		sum+=a;
		if(j==i){
			i+=++a;//增加步长
		}
	}
	cout<<sum;
}

三.纯数学解法

真正的好戏上演了
使用这个解法,是 O ( 1 ) O(1) O(1)的时间复杂度
但是 还有几个前置芝士需要补充

等差数列求和公式

( a 1 + a n ) n d 2 \frac{(a_{1}+a_{n})nd}{2} 2(a1+an)nd
不会的请自己去问高斯好吗?

平方和公式

1 1 1 n n n的平方和为
1 2 + 2 2 + 3 2 + . . . . . . + n 2 1^2+2^2+3^2+......+n^2 12+22+32+......+n2
拆分一下,就是
1 + 2 + 2 + 3 + 3 + 3 + . . . . . . + n + n + . . . + n 1+2+2+3+3+3+......+n+n+...+n 1+2+2+3+3+3+......+n+n+...+n
再合并一下,就是
( 1 + 2 + 3 + . . . + n ) + ( 2 + 3 + . . . + n ) + . . . + n (1+2+3+...+n)+(2+3+...+n)+...+n (1+2+3+...+n)+(2+3+...+n)+...+n
再回去看一眼等差数列求和公式
整理得到
( 1 + n ) ( n − 1 + 1 ) 2 + ( 2 + n ) ( n − 2 + 1 ) 2 + . . . . . . + ( n + n ) ( n − n + 1 ) 2 = ∑ i = 1 n ( i + n ) ( n − i + 1 ) 2 \frac{(1+n)(n-1+1)}{2}+\frac{(2+n)(n-2+1)}{2}+......+\frac{(n+n)(n-n+1)}{2}=\sum_{i=1}^{n}\frac{(i+n)(n-i+1)}{2} 2(1+n)(n1+1)+2(2+n)(n2+1)+......+2(n+n)(nn+1)=i=1n2(i+n)(ni+1)
再整理一下,就是
n 2 + n 2 + n 2 + n − 2 2 + n 2 + n − 6 2 + . . . + n 2 + n − ( n − 1 ) n 2 = ∑ i = 1 n n 2 + n − i ( i − 1 ) 2 \frac{n^2+n}{2}+\frac{n^2+n-2}{2}+\frac{n^2+n-6}{2}+...+\frac{n^2+n-(n-1)n}{2}=\sum_{i=1}^{n}\frac{n^2+n-i(i-1)}{2} 2n2+n+2n2+n2+2n2+n6+...+2n2+n(n1)n=i=1n2n2+ni(i1)
继续拆开,就可以发现原式为
( n 2 + n 2 ) n − 1 2 ( 1 ∗ 2 + 2 ∗ 3 + 3 ∗ 4 + . . . + ( n − 1 ) n ) (\frac{n^2+n}{2})n-\frac{1}{2}(1*2+2*3+3*4+...+(n-1)n) (2n2+n)n21(12+23+34+...+(n1)n)
前面这一段很好求,为
n 3 + n 2 2 \frac{n^3+n^2}{2} 2n3+n2
后面这一段需要用到整数裂项
合并后为
1 2 { 1 3 [ 1 ∗ 2 ∗ 3 − 0 ∗ 1 ∗ 2 + 2 ∗ 3 ∗ 4 − 1 ∗ 2 ∗ 3 + . . . + ( n − 1 ) n ( n + 1 ) − ( n − 2 ) ( n − 1 ) n ] } \frac{1}{2}\left \{\frac{1}{3}[1*2*3-0*1*2+2*3*4-1*2*3+...+(n-1)n(n+1)-(n-2)(n-1)n] \right \} 21{31[123012+234123+...+(n1)n(n+1)(n2)(n1)n]}
= ( n − 1 ) n ( n + 1 ) 6 = n 3 − n 6 =\frac{(n-1)n(n+1)}{6}=\frac{n^3-n}{6} =6(n1)n(n+1)=6n3n
代入原式得
n 3 + n 2 2 − n 3 − n 6 = 2 n 3 + 3 n 2 + n 6 \frac{n^3+n^2}{2}-\frac{n^3-n}{6}=\frac{2n^3+3n^2+n}{6} 2n3+n26n3n=62n3+3n2+n
分母提一个 n n n
2 n 3 + 3 n 2 + n 6 = ( 2 n 2 + 3 n + 1 ) n 6 \frac{2n^3+3n^2+n}{6}=\frac{(2n^2+3n+1)n}{6} 62n3+3n2+n=6(2n2+3n+1)n
做一个十字交叉,得到最终的等式
∑ i = 1 n n 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^{n}n^2=\frac{n(n+1)(2n+1)}{6} i=1nn2=6n(n+1)(2n+1)
所以,不会的现在看懂没有?

构思过程

因为原式为 1 + 2 + 2 + 3 + 3 + 3 + . . . . . . + ( n − 1 ) + ( n − 1 ) + . . . + ( n − 1 ) + n + n + . . . 1+2+2+3+3+3+......+(n-1)+(n-1)+...+(n-1)+n+n+... 1+2+2+3+3+3+......+(n1)+(n1)+...+(n1)+n+n+...
我们把它分成两段 1 + 2 + 2 + 3 + 3 + 3 + . . . . . . + ( n − 1 ) + ( n − 1 ) + . . . + ( n − 1 ) 1+2+2+3+3+3+......+(n-1)+(n-1)+...+(n-1) 1+2+2+3+3+3+......+(n1)+(n1)+...+(n1) n + n + . . . n+n+... n+n+...
那么 ( n − 1 ) (n-1) (n1)怎么求呢?
还是等差数列求和公式
因为总天数为 k k k
少了得金币数为 n n n的几天
所以有不等式 ( 1 + a ) a 2 ≤ k \frac{(1+a)a}{2}≤k 2(1+a)ak
a 2 + a ≤ 2 k a^2+a≤2k a2+a2k
∴ ( a 2 + a ) ≤ ( 2 k ) \therefore \sqrt (a^2+a)≤\sqrt(2k) ( a2+a)( 2k)
∴ ( 2 k ) ≈ ( a 2 ) = a \therefore \sqrt(2k)\approx\sqrt(a^2)=a ( 2k)( a2)=a
但是这样一点也不精确
所以,我们先求出不精确的值,再用不精确的值去求出较精确的值
∵ a 2 + a ≤ 2 k \because a^2+a≤2k a2+a2k
∴ a 2 ≤ 2 k − a \therefore a^2≤2k-a a22ka
∴ ( a 2 ) ≤ ( 2 k − a ) \therefore \sqrt (a^2)≤\sqrt(2k-a) ( a2)( 2ka)
∴ ( a 2 ) ≤ ( 2 k − a ) \therefore \sqrt (a^2)≤\sqrt(2k-a) ( a2)( 2ka)
a ≈ ( 2 k − a ) a\approx\sqrt(2k-a) a( 2ka)
所以向下取整就能得到正确的答案
或许有人不信,说:你这个取的是近似值,万一有一个大于 ( n + 1 ) (n+1) (n+1)了呢
这是不可能的,我现在证明给你看
1 + 2 + 2 + 3 + 3 + 3 + . . . . . . + ( n − 1 ) + ( n − 1 ) + . . . + ( n − 1 ) + n + n + . . . 1+2+2+3+3+3+......+(n-1)+(n-1)+...+(n-1)+n+n+... 1+2+2+3+3+3+......+(n1)+(n1)+...+(n1)+n+n+...后面有 m m m n n n
∴ k = a 2 + a 2 + m \therefore k=\frac{a^2+a}{2}+m k=2a2+a+m
∴ 2 k = a 2 + a + 2 m \therefore 2k=a^2+a+2m 2k=a2+a+2m
∴ ( 2 k ) = ( a 2 + a + 2 m ) \therefore \sqrt(2k)=\sqrt(a^2+a+2m) ( 2k)=( a2+a+2m)
∵ a ≈ ( 2 k ) \because a\approx\sqrt(2k) a( 2k)
∴ ( 2 k − a ) ≈ ( 2 k − ( 2 k ) ) \therefore \sqrt(2k-a)\approx\sqrt(2k-\sqrt(2k)) ( 2ka)( 2k( 2k))
∵ ( 2 k ) = ( a 2 + a + 2 m ) \because \sqrt(2k)=\sqrt(a^2+a+2m) ( 2k)=( a2+a+2m)
∴ ( 2 k − ( 2 k ) ) = ( a 2 + a + 2 m − ( a 2 + a + 2 m ) ) \therefore \sqrt(2k-\sqrt(2k))=\sqrt(a^2+a+2m-\sqrt(a^2+a+2m)) ( 2k( 2k))=( a2+a+2m( a2+a+2m))
∵ 1 ≤ m < ( a + 1 ) \because 1≤m<(a+1) 1m<(a+1)
m = 1 m=1 m=1
( 2 k − ( 2 k ) ) = ( a 2 + a + 2 − ( a 2 + a + 2 ) ) \sqrt(2k-\sqrt(2k))=\sqrt(a^2+a+2-\sqrt(a^2+a+2)) ( 2k( 2k))=( a2+a+2( a2+a+2))
∵ a < ( a 2 + a ) < a + 1 \because a<\sqrt(a^2+a)<a+1 a<( a2+a)<a+1
∴ 当 a > 2 时 a < ( a 2 + a + 2 ) < a + 1 \therefore 当a>2时a<\sqrt(a^2+a+2)<a+1 a>2a<( a2+a+2)<a+1
( a 2 + a + 2 ) = a \sqrt(a^2+a+2)=a ( a2+a+2)=a
( 2 k − ( 2 k ) ) = ( a 2 + 2 + a − a ) = ( a 2 + 2 ) \sqrt(2k-\sqrt(2k))=\sqrt(a^2+2+a-a)=\sqrt(a^2+2) ( 2k( 2k))=( a2+2+aa)=( a2+2)
( a 2 + a + 2 ) = a + 1 \sqrt(a^2+a+2)=a+1 ( a2+a+2)=a+1
( 2 k − ( 2 k ) ) = ( a 2 + a + 2 − ( a + 1 ) ) = ( a 2 + 1 ) \sqrt(2k-\sqrt(2k))=\sqrt(a^2+a+2-(a+1))=\sqrt(a^2+1) ( 2k( 2k))=( a2+a+2(a+1))=( a2+1)
∴ ( a 2 + 1 ) < ( 2 k − ( 2 k ) ) < ( a 2 + 2 ) \therefore \sqrt(a^2+1)<\sqrt(2k-\sqrt(2k))<\sqrt(a^2+2) ( a2+1)<( 2k( 2k))<( a2+2)
m = ( a + 1 ) m=(a+1) m=(a+1)
( 2 k − ( 2 k ) ) = ( a 2 + a + a + 1 ) = ( ( a + 1 ) 2 ) = a + 1 \sqrt(2k-\sqrt(2k))=\sqrt(a^2+a+a+1)=\sqrt((a+1)^2)=a+1 ( 2k( 2k))=( a2+a+a+1)=( (a+1)2)=a+1
∵ 1 ≤ m < ( a + 1 ) \because 1≤m<(a+1) 1m<(a+1)
∴ a < ( a 2 + 1 ) < ( 2 k − ( 2 k ) ) < ( a + 1 ) \therefore a<\sqrt(a^2+1)<\sqrt(2k-\sqrt(2k))<(a+1) a<( a2+1)<( 2k( 2k))<(a+1)
∴ ( 2 k − ( 2 k ) ) − a < 1 \therefore \sqrt(2k-\sqrt(2k))-a<1 ( 2k( 2k))a<1
证毕
好,现在开始上代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	scanf("%d",&n);
	double a=sqrt(2*n);//求近似值
	a=(int)sqrt(2*n-a);//求准确值
	//double a=sqrt(2*n-sqrt(2*n))
	int c=(a*(a+1)*(2*a+1))/6;//平方和公式
	int d=(n-(1+a)*a/2)*(a+1);//计算剩余
	printf("%d",c+d);
	return 0; 
}

至此,这道题已经讲完了,感谢大家的观看
特别鸣谢:高斯

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值