G. Hits Different
G. Hits Different
In a carnival game, there is a huge pyramid of cans with rows, numbered in a regular pattern as shown.
If can 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 . This causes all cans that are stacked on top of this can to fall (that is, can falls, then the cans directly above fall, then the cans directly above those cans, and so on). For example, the picture above shows the cans that would fall if can is hit.
What is the sum of the numbers on all cans that fall? Recall that .
Input
The first line contains an integer () — the number of test cases.
The only line of each test case contains a single integer () — it means that the can you hit has label .
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
In the second test case, only the can labeled falls, so the answer is .
In the third test case, the cans labeled and fall, so the answer is .
In the fourth test case, the cans labeled and fall, so the answer is .
In the fifth test case, the cans labeled , , and fall, so the answer is .
解题思路
我们先对金字塔转换成矩阵的形式,结果如下图:
以上图为例子,如果选择号的格子,此时对应的坐标为(矩阵坐标系)。那么在金字塔中的上一行与号格子有接触的是号和号格子,因此我们想到能不能利用号和号格子的结果来得到号格子的结果呢?
定义表示从号格子往上能走到的与其接触的格子的值之和。先给出结论,。为什么要减去一个?这是因为从号格子往上走会经过号格子与号格子,从号格子往上走会经过号格子与号格子,因此会有重复的部分,即,因此减去即可,有容斥原理的思想在里面。
递推公式知道了,那么接下来问题是我知道了号格子,怎么得到上面的两个格子的编号呢?在矩阵的表示中可以发现第行恰好有个格子,因此如果知道当前号格子的坐标为,那么上面两个的坐标就是和,要减去的格子坐标是。而已知坐标推格子编号还是很容易的,有公式,因此递推公式就变成了
可以发现每次用到的都是上一行的结果,因此我们可以从第行开始往下递推(其中)。然后可能往上走有些格子并不存在,此时公式就有所变化了,如果对应的格子不存在那么直接不考虑该项结果即可,对应的细节处理见代码。
我们直接预处理出来以内的,询问的时候直接查表,因此计算量为。
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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17381722.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效