G. Hits Different

G. Hits Different

In a carnival game, there is a huge pyramid of cans with 2023 rows, numbered in a regular pattern as shown.

If can 92 is hit initially, then all cans colored red in the picture above would fall.

You throw a ball at the pyramid, and it hits a single can with number n2. This causes all cans that are stacked on top of this can to fall (that is, can n2 falls, then the cans directly above n2 fall, then the cans directly above those cans, and so on). For example, the picture above shows the cans that would fall if can 92 is hit.

What is the sum of the numbers on all cans that fall? Recall that n2=n×n.

Input

The first line contains an integer t (1t1000) — the number of test cases.

The only line of each test case contains a single integer n (1n106) — it means that the can you hit has label n2.

Output

For each test case, output a single integer — the sum of the numbers on all cans that fall.

Please note, that the answer for some test cases won't fit into 32-bit integer type, so you should use at least 64-bit integer type in your programming language (like long long for C++). For all valid inputs, the answer will always fit into 64-bit integer type.

Example

input

复制代码
10
9
1
2
3
4
5
6
10
1434
1000000
复制代码

output

复制代码
156
1
5
10
21
39
46
146
63145186
58116199242129511
复制代码

Note

The first test case is pictured in the statement. The sum of the numbers that fall is 12+22+32+52+62+92=1+4+9+25+36+81=156.

In the second test case, only the can labeled 12 falls, so the answer is 12=1.

In the third test case, the cans labeled 12 and 22 fall, so the answer is 12+22=1+4=5.

In the fourth test case, the cans labeled 12 and 32 fall, so the answer is 12+32=1+9=10.

In the fifth test case, the cans labeled 12, 22, and 42 fall, so the answer is 12+22+42=1+4+16=21.

 

解题思路

  我们先对金字塔转换成矩阵的形式,结果如下图:

  以上图为例子,如果选择13号的格子,此时对应的坐标为(5,3)(矩阵坐标系)。那么在金字塔中的上一行与13号格子有接触的是8号和9号格子,因此我们想到能不能利用8号和9号格子的结果来得到13号格子的结果呢?

  定义f(x)表示从x号格子往上能走到的与其接触的格子的值之和。先给出结论,f(13)=132+f(8)+f(9)f(5)。为什么要减去一个f(5)?这是因为从8号格子往上走会经过4号格子与5号格子,从9号格子往上走会经过5号格子与6号格子,因此f(8)+f(9)会有重复的部分,即f(5),因此减去即可,有容斥原理的思想在里面。

  递推公式知道了,那么接下来问题是我知道了x号格子,怎么得到上面的两个格子的编号呢?在矩阵的表示中可以发现第i行恰好有i个格子,因此如果知道当前x号格子的坐标为(i,j),那么上面两个的坐标就是(i1,j)(i1,j1),要减去的格子坐标是(i2,j1)。而已知坐标推格子编号还是很容易的,有公式g(i,j)=k=1i1k+j=i(i1)2+j,因此递推公式就变成了f(g(i,j))=g2(i,j)+f(g(i1,j))+f(g(i1,j1))f(g(i2,j1))

  可以发现每次用到的都是上一行的结果,因此我们可以从第2行开始往下递推(其中f(1)=1)。然后可能往上走有些格子并不存在,此时公式就有所变化了,如果对应的格子不存在那么直接不考虑该项结果即可,对应的细节处理见代码。

  我们直接预处理出来106以内的f(x),询问的时候直接查表,因此计算量为O(106+T)

  AC代码如下:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 1e6 + 10;
 7 
 8 LL f[N];
 9 
10 void init() {
11     f[1] = 1;   // 边界情况f(1)=1
12     for (int i = 2, k = 2; k < N; i++) {    // 从第2行开始枚举,k是要枚举的格子编号
13         for (int j = 1; j <= i; j++, k++) { // 第i行最多有i列,即纵坐标不超过横坐标
14             f[k] = 1ll * k * k;
15             if (i - 1 > 0) {    // 上一行(第i-1行)存在
16                 if (j <= i - 1) f[k] += f[(i - 2) * (i - 1) / 2 + j];   // 列不超过行,存在格子(i-1,j)
17                 if (j - 1 > 0) {    // 首先必然有j-1 <= i-1,然后还要保证j-1 > 0,没有越界,才存在格子(i-1,j-1)
18                     f[k] += f[(i - 2) * (i - 1) / 2 + j - 1];
19                     if (i - 2 > 0 && j - 1 <= i - 2) f[k] -= f[(i - 3) * (i - 2) / 2 + j - 1];  // 第i-2行存在且列不超过行(已经保证j-1 > 0了)
20                 }
21             }
22         }
23     }
24 }
25 
26 void solve() {
27     int n;
28     scanf("%d", &n);
29     printf("%lld\n", f[n]);
30 }
31 
32 int main() {
33     init();
34     int t;
35     scanf("%d", &t);
36     while (t--) {
37         solve();
38     }
39     
40     return 0;
41 }
复制代码

 

参考资料

  Codeforces Round 871 (Div. 4) A - H:https://zhuanlan.zhihu.com/p/627396904

posted @   onlyblues  阅读(84)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示