《深入浅出进阶篇》——空间换时间优化——P2671 求和

链接:https://www.luogu.com.cn/problem/P2671

上题干:

题目描述

一条狭长的纸带被均匀划分出了n个格子,格子编号从11到n。每个格子上都染了一种颜色colori​用[1,m]当中的一个整数表示),并且写了一个数字numberi​。

定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:

  1. xyz是整数,x<y<z,y−x=z−y

  2. colorx=colorz

满足上述条件的三元组的分数规定为(x+z)×(numberx​+numberz​)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。

输入格式

第一行是用一个空格隔开的两个正整数n表式纸带上格子的个数,m表纸带上颜色的种类数。

第二行有n用空格隔开的正整数,第i数字number表纸带上编号为i格子上面写的数字。

第三行有n用空格隔开的正整数,第i数字color表纸带上编号为i格子染的颜色。

输出格式

一个整数,表示所求的纸带分数除以1000710007所得的余数。

输入输出样例

输入 #1复制

6 2
5 5 3 2 2 2
2 2 1 1 2 1

输出 #1复制

82

输入 #2复制

15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1

输出 #2复制

1388

说明/提示

【输入输出样例 1 说明】

纸带如题目描述中的图所示。

所有满足条件的三元组为: (1,3,5),(4,5,6)(1,3,5),(4,5,6)。

所以纸带的分数为(1+5)×(5+2)+(4+6)×(2+2)=42+40=82(1+5)×(5+2)+(4+6)×(2+2)=42+40=82。

对于第 11 组至第 22 组数据,1≤n≤100,1≤m≤5;

对于第33 组至第 44 组数据, 1≤n≤3000,1≤m≤100;

对于第 55 组至第66组数据, 1≤n≤100000,1≤m≤100000,且不存在出现次数超过20的颜色;

对 于 全 部 1010 组 数 据 , 1≤n≤100000,1≤m≤100000,1≤colori​≤m,1≤numberi​≤100000

从这道题里,我们可以学到很多东西。

因为每个格子的编号是从1开始的,所以我们定义两个数组,a【i】表示 第i个格子内的数字,

b【i】表示第i个格子的颜色。

然后,这道题给了我们一个三元组(x,y,z),三个编号为x,y,z的格子。

要求这个三元组满足下面两个条件:

第一个条件是,这个三元组内部是严格升序的,并且,y-x=z-y

严格升序都能理解,那么我们接下来研究一下y-x=z-y这个条件想表达什么。

首先呢,不难看出它是一个等差数列。即x,y,z满足等差性质

那么假设公差为d,则有:x+2d=z,因为2d是一个偶数,所以x必然与z共奇偶。

请把这条性质记住。我们为什么会想到这个呢?因为我们是站在枚举复杂度的角度来看的。

假设我们要找到所有满足条件的x,y,z,那么简单的三重枚举就行了,但是会超时。

所以我们必须要找出优化的枚举操作。并带着目的性去审视题目给的条件。

第二个条件是:在(x,y,z)中,编号x的格子颜色要等于,编号为z的格子的颜色

即b【x】=b【z】

足这两个条件的三元组就可以计入答案,

每一组合法的三元组对答案的贡献是(x+z)*(a【x】+a【z】)

那么这道题到这就结束了吗?

不,还远远没有。

因为以我们现在推出来的条件,我们需要每次枚举x,z的位置(复杂度为O(n^2)),并且判断x,z的奇偶性,颜色是否相同。

这样做仍然无法通过本题(没错就是这么变态)

所以我们还要优化,但是还有哪里能优化呢?我们已经优化了条件,但是你有没有想过,计算答案这个过程是可以优化的。

每一个合法的三元组对答案的贡献可以展开成:x*a【x】+x*a【z】+z*a【x】+z*a【y】

那么x对答案的贡献是什么呢?x*a【x】+x*a【z】

我们简化一下问题:不考虑颜色是否相同,只考虑奇偶性是否相同

假设一对合法三元组为(1,2,3)那么1对答案的贡献是 1*a【1】+1*a【3】;

然后枚举z,当x=1的时候,z可以是5,7,9,11,13......

所以1对答案的贡献就是:1*a【1】+1*a【3】)+(1*a【1】1*a【5】)+(1*a【1】+1*a【7】)......

假设z枚举到7为止,也就是说如果有4个条件相同的元素(1,3,5,7)那么

1对答案的贡献:    3* (1*a【1】)+a【3】+a【5】+a【7】

等价于: 2*(1*a【1】)+(a【1】+a【3】+a【5】+a【7】)

3对答案的贡献:    3*(3*a【3】)+ 3a【1】+3a【5】+3a【7】

等价于:    2*(3*a【3】)+ 3(a【1】+a【3】+a【5】+a【7】)

我们可以把这个化成i的时候的一般式子,即i对于答案的贡献是 ( 共奇偶的格子数-2)*a【1】+i*(所有的共奇偶的格子上的数字和)

那么把这个东西一般化呢?即 任何 i 对答案的贡献是 a【i】*(满足同一种条件的格子数-2)+i*(满足同一种条件的格子数上面的数字之和)

让我们回到我们的问题,合法的三元组必须满足颜色相同,奇偶相同的性质

所以我们可以同理推理出来: 任何i对答案的贡献都是 a【i】*(共奇偶,且共颜色 的格子的总个数-2)+i*(共奇偶,共颜色的格子上面的数字之和)

所以我们只需要提前算出,共奇偶且共颜色的每个格子上的数字之和,和共奇偶且共颜色的格子总数。

用一个数组来存《共奇偶且共颜色的每个格子上的数字之和》   那么就有前缀和式子: sum【颜色】【奇偶】+= 满足这个条件的格子上的数字

也就是 sum[b[i][i%2]+= a[i];

另一个数组来存《共奇偶且共颜色的格子总数》 有 桶排序 ans【颜色】【奇偶】++;

也就是ans[b[i]][i%2]++;

然后我们就可以线性地求答案了。

只需要枚举i=1~n,每次计算答案,然后取模就可以了 。

代码如下:


const int N = 1e5 + 10;
const int mod = 10007;
int sum, n, m;
int a[N], b[N];
int sum1[N][3];//同色同奇偶的个数
int num[N][3];//同色奇偶的编号和
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> a[i];//输入编号
	for (int i = 1; i <= n; i++)
	{
		cin >> b[i];
		sum1[b[i]][i % 2]++;
		num[b[i]][i % 2] = (num[b[i]][i % 2]+a[i]) % mod;
	}
	for (int i = 1; i <= n; i++)
	{ 
		sum = (sum+ i *( (sum1[b[i]][i % 2] - 2) * a[i]%mod + num[b[i]][i % 2]) )%mod;
	}
	cout << sum;
}


  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

louisdlee.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值