G. Hits Different
Posted onlyblues
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 $9^2$ 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 $n^2$. This causes all cans that are stacked on top of this can to fall (that is, can $n^2$ falls, then the cans directly above $n^2$ fall, then the cans directly above those cans, and so on). For example, the picture above shows the cans that would fall if can $9^2$ is hit.
What is the sum of the numbers on all cans that fall? Recall that $n^2 = n \\times n$.
Input
The first line contains an integer $t$ ($1 \\leq t \\leq 1000$) — the number of test cases.
The only line of each test case contains a single integer $n$ ($1 \\leq n \\leq 10^6$) — it means that the can you hit has label $n^2$.
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 $$1^2 + 2^2 + 3^2 + 5^2 + 6^2 + 9^2 = 1 + 4 + 9 + 25 + 36 + 81 = 156.$$
In the second test case, only the can labeled $1^2$ falls, so the answer is $1^2=1$.
In the third test case, the cans labeled $1^2$ and $2^2$ fall, so the answer is $1^2+2^2=1+4=5$.
In the fourth test case, the cans labeled $1^2$ and $3^2$ fall, so the answer is $1^2+3^2=1+9=10$.
In the fifth test case, the cans labeled $1^2$, $2^2$, and $4^2$ fall, so the answer is $1^2+2^2+4^2=1+4+16=21$.
解题思路
我们先对金字塔转换成矩阵的形式,结果如下图:
以上图为例子,如果选择$13$号的格子,此时对应的坐标为$(5,3)$(矩阵坐标系)。那么在金字塔中的上一行与$13$号格子有接触的是$8$号和$9$号格子,因此我们想到能不能利用$8$号和$9$号格子的结果来得到$13$号格子的结果呢?
定义$f(x)$表示从$x$号格子往上能走到的与其接触的格子的值之和。先给出结论,$f(13) = 13^2 + 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)$,那么上面两个的坐标就是$(i-1,j)$和$(i-1,j-1)$,要减去的格子坐标是$(i-2,j-1)$。而已知坐标推格子编号还是很容易的,有公式$g(i,j) = \\sum\\limits_k=1^i-1k+j = \\dfraci \\cdot (i-1)2+j$,因此递推公式就变成了$$f(g(i,j)) = g^2(i,j) + f(g(i-1,j)) + f(g(i-1,j-1)) - f(g(i-2,j-1))$$
可以发现每次用到的都是上一行的结果,因此我们可以从第$2$行开始往下递推(其中$f(1)=1$)。然后可能往上走有些格子并不存在,此时公式就有所变化了,如果对应的格子不存在那么直接不考虑该项结果即可,对应的细节处理见代码。
我们直接预处理出来$10^6$以内的$f(x)$,询问的时候直接查表,因此计算量为$O(10^6 + T)$。
AC代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e6 + 10; LL f[N]; void init() f[1] = 1; // 边界情况f(1)=1 for (int i = 2, k = 2; k < N; i++) // 从第2行开始枚举,k是要枚举的格子编号 for (int j = 1; j <= i; j++, k++) // 第i行最多有i列,即纵坐标不超过横坐标 f[k] = 1ll * k * k; if (i - 1 > 0) // 上一行(第i-1行)存在 if (j <= i - 1) f[k] += f[(i - 2) * (i - 1) / 2 + j]; // 列不超过行,存在格子(i-1,j) if (j - 1 > 0) // 首先必然有j-1 <= i-1,然后还要保证j-1 > 0,没有越界,才存在格子(i-1,j-1) f[k] += f[(i - 2) * (i - 1) / 2 + j - 1]; if (i - 2 > 0 && j - 1 <= i - 2) f[k] -= f[(i - 3) * (i - 2) / 2 + j - 1]; // 第i-2行存在且列不超过行(已经保证j-1 > 0了) void solve() int n; scanf("%d", &n); printf("%lld\\n", f[n]); int main() init(); int t; scanf("%d", &t); while (t--) solve(); return 0;
参考资料
Codeforces Round 871 (Div. 4) A - H:https://zhuanlan.zhihu.com/p/627396904
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17381722.html
BigQuery(谷歌分析数据):在同一个“hits.hitNumber”中查询两个不同的“hits.customDimensions.index”
【中文标题】BigQuery(谷歌分析数据):在同一个“hits.hitNumber”中查询两个不同的“hits.customDimensions.index”【英文标题】:BigQuery (Google Analytics data):query two different 'hits.customDimensions.index' in the same 'hits.hitNumber' 【发布时间】:2020-01-09 16:55:22 【问题描述】:我的目标:
如果以下两个 hits.customDimensions.index 和关联的 hits.customDimensions.value 出现在相同的 hits.hitNumber 中,则会话计数为 1(如果主查询仍然嵌套,则每行都是 1 个会话):
['hits.customDimensions.index' = 43 关联 'hits.customDimensions.value' IN ('login', 'payment', 'order', 'thankyou')] AND ['hits.customDimensions.index' = 10 关联 'hits.customDimensions.value' = 'checkout' [在同一个 hits.hitNumber]
我的问题:
我不知道如何在没有不同 WITH 表的情况下在一个子查询中查询相同 hits.hitNumber 中的两个不同 hits.customDimensions.value。如果可能的话,我敢肯定,查询将非常简单和简短。因为我不知道如何在子查询中查询这个用例,所以我使用了一个总计为 5 个 WITH 表的解决方法。 我希望有一种查询此用例的简单方法
解释变通方法查询:
Table1:查询除“problem-metric”之外的所有内容
表 2-3:每个表查询一个 hits.customDimensions.index,关联的 hits.customDimensions.value 过滤为正确的值,sessionId 和 hitNumber
table4:根据日期、sessionID 和 hitNumber 将表 2 与表 3 左连接。基本上,如果 hitNumber 与 table2 和 table3 中的 sessionId 相结合,我算 1
table5:left join table1和table4来合并数据
#Table1 - complete data except session_atleast_loginCheckout
WITH
prepared_data AS (
SELECT
date,
SUM((SELECT 1 FROM UNNEST(hits) WHERE CAST(eCommerceAction.action_type AS INT64) BETWEEN 4 AND 6 LIMIT 1)) AS sessions_atleast_basket,
#insert in this row query for sessions_atleast_loginCheckout
SUM((SELECT 1 FROM UNNEST(hits) as h, UNNEST(h.customDimensions) as hcd WHERE index = 43 AND value IN ('payment', 'order', 'thankyou') LIMIT 1)) AS sessions_atleast_payment,
FROM
`big-query-221916.172008714.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND totals.visits = 1
GROUP BY
date
#Table2 - data for hits.customDimensions.index = 10 AND associated hits.customDimensions.value = 'checkout' with hits.hitNumber and sessionId (join later based on hitNumber and sessionId)
loginCheckout_index10_pagetype_data AS (
SELECT
date AS date,
CONCAT(fullVisitorId, '/', CAST( visitStartTime AS STRING)) AS sessionId,
h.hitNumber AS hitNumber,
IF(hcd.value IS NOT NULL, 1, NULL) AS pagetype_checkout
FROM
`big-query-221916.172008714.ga_sessions_*` AS o, UNNEST(hits) as h, UNNEST(h.customDimensions) as hcd
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND hcd.index = 10 AND VALUE = 'checkout' AND h.type = 'PAGE' AND totals.visits = 1),
#Table3 - data for hits.customDimensions.index = 43 AND associated hits.customDimensions.value IN ('login', 'register', 'payment', 'order','thankyou') with hits.hitNumber and sessionId (join later based on hitNumber and sessionId)
loginCheckout_index43_pagelevel1_data AS (
SELECT
date AS date,
CONCAT(fullVisitorId, '/', CAST( visitStartTime AS STRING)) AS sessionId,
h.hitNumber AS hitNumber,
IF(hcd.value IS NOT NULL, 1, NULL) AS pagelevel1_login_to_thankyou
FROM
`big-query-221916.172008714.ga_sessions_*` AS o, UNNEST(hits) as h, UNNEST(h.customDimensions) as hcd
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND hcd.index = 43 AND VALUE IN ('login', 'register', 'payment', 'order', 'thankyou') AND h.type = 'PAGE'
),
#table4 - left join table2 and table 3 on sessionId and hitNumber to get sessions_atleast_loginCheckout
loginChackout_output_data AS(
SELECT
a.date AS date,
COUNT(DISTINCT a.sessionId) AS sessions_atleast_loginCheckout
FROM
loginCheckout_index10_pagetype_data AS a
LEFT JOIN
loginCheckout_index43_pagelevel1_data AS b
ON
a.date = b.date AND
a.sessionId = b.sessionId AND
a.hitNumber = b.hitNumber
WHERE
pagelevel1_login_to_thankyou IS NOT NULL
GROUP BY
date
#table5 - leftjoin table1 with table4 to get all data together
SELECT
prep.date,
prep.sessions_atleast_basket,
log.sessions_atleast_loginCheckout,
prep.sessions_atleast_payment
FROM
prepared_data AS prep
LEFT JOIN
loginChackout_output_data as log
ON
prep.date = log.date AND
【问题讨论】:
为什么要减少 CTE 的数量?在我看来,你在每一个中都封装了不同的逻辑,这将使你的队友(或 6 个月后的你)更容易阅读。新线路很便宜,脑力很贵。 为了安全起见,我目前一个人,经验不足。我也不确定是否有其他方法(可以理解和合乎逻辑)。 【参考方案1】:这有点像《盗梦空间》,但记住unnest()
的输入是一个数组而输出是表格行可能会有所帮助...
SELECT
SUM(totals.visits) as sessions
FROM
`big-query-221916.172008714.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND FORMAT_DATE('%Y%m%d',DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
AND -- the following two hits.customDimensions.index and associated hits.customDimensions.value appear in the same hits.hitNumber
(SELECT COUNT(1)>0 as hitsCountMoreThanZero FROM UNNEST(hits) AS h
WHERE
-- index 43, value IN ('login', 'payment', 'order', 'thankyou')
(select count(1)>0 from unnest(h.customdimensions) where index=43 and value IN ('login', 'payment', 'order', 'thankyou'))
AND
-- index 10, value = 'checkout'
(select count(1)>0 from unnest(h.customdimensions) where index=10 and value='checkout')
)
GROUP BY
date
【讨论】:
以上是关于G. Hits Different的主要内容,如果未能解决你的问题,请参考以下文章
BigQuery(谷歌分析数据):在同一个“hits.hitNumber”中查询两个不同的“hits.customDimensions.index”
Google Analytics 和 BigQuery 之间的会话不匹配,同时将 hits 和 hits.product 取消嵌套