十年 |

daiyulong

园龄:1年3个月粉丝:1关注:0

【题解】U405180 计算平方和

欢迎大家在评论区抢前排!

Part 0 目录 / Contents

Part 1 题目大意 / Item content

题目链接

共有 T 组数据。给定 L,R ,请你计算 L2+(L+1)2+(L+2)2++(R2)2+(R1)2

对于 100% 的数据:1T106, 1LR1012

Part 2 题解 / Solution

首先我们看一下数据范围(见上)。首先 T106 ,那么算法的时间复杂度总体只可以是 O(n) ,每一组数据的计算的时间复杂度就只能是 O(1) 。然后是 LR1012 ,这个就是这道题目的难点,也是这道题为什么难度是 普及/提高- 的原因了。这个数据的计算结果开到 long long 也不行。所以这就考虑到了我们日常的积累。C + + 中有一个整数类型是完全可以支持这个数据结构的,那就是 __int128 。我们先来一起了解一下这个数据结构。

Part 2.1 C + + 神奇整数类型之 __int128 / C + + Magic integer type __int128

__int128 就是占用了 128 字节的整数存储类型。由于是二进制,范围就是 212721271 ,如果使用了 unsigned __int128 ,则范围变成 021281 ,即约 39 位数,这在一定程度上可以替代高精度运算实现大数运算,而且操作难度更低,所以在数据范围不超过的情况下,都可以使 __int128

由于 __int128 只能实现四则运算,不能用 cin,cout,scanf,printf 输入输出,我们首先应该写个快读和快写的函数。

Part 2.1.1 快读 / fast read

快读模板(函数 read

__int128 read() {
    __int128 x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') {
          f=-1;
          c=getchar();
        }
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

Part 2.1.2 快写 / fast write

快写模板(函数 print

void print(__int128 x) {
     if(x<0) {
       putchar('-');
       x=-x;
     }
     if(x>9) {
       print(x/10);
     }
     putchar(x%10+'0');
}

解决完了数据类型的问题,我们该想想算法。怎样在 O(1) 的时间复杂度内计算 L2+(L+1)2+(L+2)2++(R2)2+(R1)2 呢?我相信,聪明的你一定想到了数学。让我们一起在评论区打出 数学好闪,拜谢数学! 这几个字(怎么说说就说出这种话)! 让我们来探索一下数学的奥秘!

Part 2.2 平方和公式 / Sum of squaresformula

首先我们知道一个基础公式(这里我就不再赘述,不会的同学可以自行去网上查找):

12+22+32++(n2)2+(n1)2+n2=n×(n+1)×(2×n+1)6

然后我们知道,线段的某个区域的长度是这么求的。

|_____________________________________________|
           L             R

LR=RL+1

这个结论我们不难想到也可以运用到平方和公式上。我们可以下此结论:

L2+(L+1)2+(L+2)2++(R2)2+(R1)2=sum(L,R) ,则 sum(L,R)=sum(1,R)sum(1,L)+L2

更详细的推导:

    sum(L,R)

=sum(1,R)sum(1,L)+L2

=R×(R+1)×(2×R+1)6L×(L+1)×(2×L+1)6+L2

好了,推完了,结论就是:

L2+(L+1)2+(L+2)2++(R2)2+(R1)2=R×(R+1)×(2×R+1)6L×(L+1)×(2×L+1)6+L2

这样就可以在 O(1) 内计算平方和了。我厉不厉害?

有了这些方法,我们所有的问题就迎刃而解了!最后献出 std 代码和标准时空。

Part 2.3 std 代码和标准时空 / Std code and standard spacetime

#include<bits/stdc++.h>
using namespace std;
__int128 x;
__int128 read() {
	__int128 num=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') {
			f=-1;
		}
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		num=num*10+c-'0';
		c=getchar();
	}
	return f*num;
}
void print(__int128 num) {
	if(x<0) {
		putchar('-');
		x*=-1;
	}
	int ans[55]={},top=0;
	do {
		ans[top++]=num%10;
		num/=10;
	} while(num);
	while(top) {
		putchar(ans[--top]+'0');
	}
}
int main() {
	int t;
	cin>>t;
	while(t--) {
		__int128 L=read(),R=read();
		print(((R*(R+1)*(2*R+1))/6)-((L*(L+1)*(2*L+1))/6)+(L*L));
		putchar('\n');
	}
	return 0;
}
时间 / Time 空间 / Memory 代码长度 / Code length 语言 / Language
2.17s 684.00KB 659B C++14 (GCC 9) O2

本文作者:daiyulong

本文链接:https://www.cnblogs.com/daiyulong/p/18008252/tijie-u405180

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   daiyulong  阅读(59)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起