1 条题解
-
0
自动搬运
来自洛谷,原作者为

Stone_Xz
且怒且悲且狂哉 ,且忘且赶且等待搬运于
2025-08-24 23:01:17,当前版本为作者最后更新于2024-07-21 11:52:07,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目传送门
简要题意
一定要把题读懂,可以结合样例和样例解释。
给定一个 进制数的每一位 ,这个数列中每个子串都可以构成一个新的的 进制数,求它们的和。并对 进制下的 取模。输出的也应该是一个 进制数。
分析:
- 还原赛时思考过程。
-
首先,题目中所有的运算都建立在 进制下,不方便,所以我们等价转换为先在十进制中进行求和、取模运算,再转换为 进制输出。
-
现在我们思考如何计算这个数列中【每个子串构成的 进制数】之和。如果暴力求解,时间复杂度怎么也要到 以上。题目中的 ,在这个时间内不足以计算每个子串的贡献,我们于是转而研究每一位的贡献。
-
一个位置能贡献多少个子串呢?每个子串都有起始位置和结束位置,对于每一个位置,它都能作为起点,结束位置可以是它右边的任何一个元素。
-
就拿样例研究,我们列出以某个位置为起点的所有子串。
- 我们发现每个位置贡献的的子串很有规律。要求整个数列中每个子串的和,那么,一个位置贡献的所有子串之和(即这个位置的贡献)是多少呢?让我们试着列出每一个位置的贡献(设第 个位置的贡献为 ):
$$\begin{aligned} ans_2 = (a_2 \times k^1 + a_3 \times k^0)\\ + (a_2 \times k^0) \\ = (10)_2 + (1)_2 \end{aligned} $$
$$\begin{aligned} ans_3 = (a_3 \times k^0)\\ = (0)_2 \end{aligned} $$- 每个位置的贡献很有规律,拿 的计算为例, 对 的贡献为 , 对 的贡献为 , 对 的贡献为 ,所以 的计算可以列为规律更加直观的一个式子:
同理:
$$ans_2 = {\color{Blue}a_2 \times (k^1 + k^0)} + {\color{Green}a_3 \times k^0} $$- 我们仍没有足够的时间暴力计算上面所有的式子,但是我们发现这其中有大量的重复,将这些重复合并,可以得到如下答案:
按照这样的的规律,就可以用 的时间计算答案了!上述式子中的括号部分计算也很简单,只需开一个变量 维护 的幂,同时维护变量
(赛时乱取的变量名...)累加每个 的幂即可(变量名与代码相符)。ps:注意多组数据,取模一定要取到位!
不然可能爆零!同时要特判 的情况输出 !代码
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 5e5 + 5, mod = 20070720; int n, k, ans, a[N]; void solve() { ans = 0; cin >> n >> k; for(int i = 1; i <= n; i++) { cin >> a[i]; a[i] %= mod; } int haha = 1, pow_ = k; for(int i = n; i >= 1; i--) { ans = (ans + a[i] % mod * i % mod * haha) % mod; haha = (haha + pow_) % mod; pow_ = (pow_ * (k % mod)) % mod; } if(ans == 0) // 特判 { cout << "0\n"; return; } // 转进制 stack<int> stk; while(ans != 0) { stk.push(ans % k); ans /= k; } while(!stk.empty()) { cout << stk.top() << " "; stk.pop(); } cout << "\n"; } signed main() { int T; cin >> T; while(T--) solve(); return 0; }- 彩蛋:在写这篇题解时,连着刷新了两下,第二下时竟然刚好碰上洛谷更新文章编辑界面,真的比之前丝滑 + 好看 + 好用太多了,专栏界面全更新了(喜
- 1
信息
- ID
- 9272
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者