小红的数组回文值
小红的数组回文值
题目描述
小红定义一个数组的回文值是:修改最少数量的元素值得该数组回文,这个次数即数组的回文值。
例如, 的回文值是 ,只需要将第二个元素修改为 即可。
现在小红拿到了一个数组,她希望你求出所有子序列的回文值之和。你能帮帮她吗?
定义子序列为从数组中从左到右取出若干个元素(可以不取、可以全取、可以不连续)形成的数组。
输入描述:
第一行输入一个整数 代表数组中的元素数量。
第二行输入 个整数 代表数组元素。
输出描述:
在一行上输出一个整数,代表所有子序列的回文值之和。由于答案可能很大,请将答案对 取模后输出。
示例1
输入
3
1 2 3
输出
4
说明
、、 和 的回文值都是 。其余子序列的回文值均为 。
示例2
输入
4
999 999 999 999
输出
0
解题思路
比赛的时候不知道范德蒙德卷积,只能写暴力骗点分了。
对于这种计数类问题可以先考虑贡献法。对于任意两个满足 且 的元素,显然在以 和 为对称元素的子序列中,因为 所以会产生 的贡献,因此 和 对答案的贡献就是满足这样要求的子序列的数量。
先假设 和 在子序列中就是对称的元素,首先对于 中的元素可以任意选择,不会改变 和 的对称性,有 种方案。然后考虑左边 和右边 的选择,显然两边应该选择同等数量的元素,那么可选的方案数量为 。因此以 和 为对称元素的子序列的数量就是 。
最后总的答案就是
如果直接暴力计算 那么总的时间复杂度为 ,显然会超时。事实上该组合式可以由范德蒙德卷积推导出 。
首先有范德蒙德卷积 ,具体证明可以参考链接。从组合意义上来讲的话,原本从大小为 的集合中选出 个元素,等价于把集合分别划分为大小为 的集合与大小为 的集合,先从大小为 的集合中取出 个元素,再从大小为 的集合中取出 个元素。
现在假设 ,那么有 。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2005, mod = 1e9 + 7;
int a[N];
int c[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= i; j++) {
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
int ret = 0;
for (int i = 1; i <= n; i++) {
int p = 1;
for (int j = i + 1; j <= n; j++) {
if (a[i] != a[j]) ret = (ret + 1ll * p * c[i - 1 + n - j][i - 1]) % mod;
p = 2ll * p % mod;
}
}
cout << ret;
return 0;
}
参考资料
题解 | #周赛59题解#:https://www.nowcoder.com/discuss/662403130013868032
范德蒙德卷积 - OI Wiki:https://oi-wiki.org/math/combinatorics/vandermonde-convolution/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18404262
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2022-09-09 【转载】论递归算法的数学原理