AcWing 463. 求和
. 求和
一、题目描述
一条狭长的纸带被均匀划分出了 个格子,格子编号从 到 。
每个格子上都染了一种颜色 (用 当中的一个整数表示),并且写了一个数字 。
定义一种特殊的三元组:,其中
都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
- 都是整数,
满足上述条件的三元组的分数规定为 。
整个纸带的分数规定为所有满足条件的三元组的分数的和。
这个分数可能会很大,你只要输出整个纸带的分数除以 所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数 和 , 代表纸带上格子的个数, 代表纸带上颜色的种类数。
第二行有 个用空格隔开的正整数,第 个数字 代表纸带上编号为 的格子上面写的数字。
第三行有 个用空格隔开的正整数,第 个数字 代表纸带上编号为 的格子染的颜色。
输出格式
共一行,一个整数,表示所求的纸带分数除以 所得的余数。
数据范围
,
输入样例:
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输出样例:
82
二、暴力枚举
分
三元组:要求满足以下两个条件:
- 都是整数,
- 那么:。由此可以枚举和的值,如果颜色相同,累加分值即可。
时间复杂度
#include <bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 10007;
int a[N], color[N];
int main() {
int n, m; // 纸带上格子的个数,纸带上颜色的种类数
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i]; // 纸带上编号为 i 的格子上面写的数字
for (int i = 1; i <= n; i++) cin >> color[i]; // 纸带上编号为 i 的格子染的颜色
int res = 0;
for (int x = 1; x <= n; x++) {
for (int y = x + 1; 2 * y - x <= n; y++) { // 因为y>=x+1,并且z<=n
int z = 2 * y - x;
if (color[x] == color[z]) // 如果color[x]=color[z]
res = (res + (2 * y) % mod * (a[x] + a[z]) % mod) % mod;
}
}
printf("%d\n", res);
return 0;
}
三、优化
读题,我们发现完全可以暴力
那这必然过不了
观察题目,对式一进行移项,发现
于是我们便可以枚举或
当然这个复杂度也是过不了的
做到这个地步,我们似乎基本没有用到颜色
于是我们便可以向颜色上靠,可以利用 分组 的思想,将同一颜色分成一组,又根据
可以 把相同颜色的分为奇偶两组
:怎么得出最后答案呢?
我们可以对分数的计算: 进行一定的处理(数学变形)
- 设为第个格子的颜色
- 为颜色为的两个奇偶分组中数字个数
设为下标,为值
将有关的式子 提出来找规律
注:共项
乘出来
将有关的式子提出来
将这个式子
得
显然可以预处理出来。
这个 是什么呢?应该是该分组中数字的总个数,这个也可以预处理出来~
#include <bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 10007;
int w[N]; // 第i个格子的数字
int c[N]; // 第i个格子的颜色
int s[N][2];
// s[i][0]:颜色为i、编号为偶数格子上数字的和
// s[i][1]:颜色为i、编号为奇数格子上数字的和
int cnt[N][2];
// cnt[i][0]:颜色为i、编号为偶数格子的个数
// cnt[i][1]:颜色为i、编号为奇数格子的个数
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> w[i]; // 第i个格子的数字
// 预处理
for (int i = 1; i <= n; i++) { // 遍历每个格子
cin >> c[i]; // 格子颜色c[i]
/*
装入不同的组中,组划分是两个规则:
① 颜色必须相同
② 奇偶性必须相同
所以,c[i]相同的放到同一个颜色组内,并且,在同一个颜色组内,奇偶数还必须相同。
s[][]:随着i的不断向后遍历,s中记录了相同颜色,相同奇偶性的格子,数字的累加和
cnt[][]:记录每个分组中的格子个数
*/
s[c[i]][i % 2] = (s[c[i]][i % 2] + w[i]) % mod; // 累加分组内数字和
cnt[c[i]][i % 2]++; // 维护分组内格子个数
}
int ans = 0;
for (int i = 1; i <= n; i++) // 枚举每个格子
/*
Q:这个格子在哪个分组里呢?
答:
(1) c[i] : 按颜色划分
(2) i % 2 : 按奇偶性划分
Q:这个分组中格子的数量是多少呢?
答: cnt[c[i]][i % 2]
*/
ans = (ans + i * ((cnt[c[i]][i % 2] - 2) * w[i] % mod + s[c[i]][i % 2])) % mod;
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2021-09-26 AcWing 861. 二分图的最大匹配
2021-09-26 AcWing 860. 染色法判定二分图
2021-09-26 AcWing 859. Kruskal算法求最小生成树
2017-09-26 使用GitLab进行落地项目的管理,并且自动更新、重启、回滚
2017-09-26 利用ssh反向代理以及autossh实现从外网连接内网服务器
2017-09-26 升级PIP源