P2671 [NOIP 2015 普及组] 求和

好题,思想很好。
首先看到这个题一个显然的思路是\(O(n^3)\)的暴力,直接枚举三个判断可行性计算贡献。

思考简单的优化,题目条件限制z-y=y-x变形可得\(y=\frac{z-x}{2}\),由于\(y\)一定是正整数,所以\(z\)\(x\)正负性相同,考虑将原数组拆分为奇数和偶数两个集合,并在两个集合中分别枚举,复杂度下降到\(O(n^2)\)

再次思考优化,将题目中计算贡献式子拆开:

\[(x+z) \times (a_x+a_z) = xa_x+xa_z+za_x+za_z \]

考虑问题变为,如何对于同样奇偶性下的每一对\((x,z)\)快速计算这个贡献呢?
注意,以下说到的均为奇偶性相同且同颜色的情况计算,对于这两种情况并不难分开处理,采用空间换时间的思想开两个数组即可。
不妨简化问题,针对n=5的情况进行判断,对于一个数列a_1,a_2,...,a_n,所有的贡献是这样的:

考察图中所有系数是\(1\)的项,发现最终答案是\((n-1)\times 1\times a_i+1\times (\sum_{j=1}^{n}a_j - a_1)\),手摸其他系数可以发现规律,对于\(i\)这一位的贡献为:

\[(n-1)\times i\times a_i + i\times (\sum_{j=1}^{n}a_j - a_i) \]

接下来就简单了,考虑\(s1\)二维数组记录某种颜色且编号为奇数或者偶数的格子数,\(s2\)记录某种颜色且编号为奇数或偶数的数字和,简单维护即可,对于每个\(i\)的答案就是i*((s2[y][i%2]-a[i])+a[i]*(s1[y][i%2])),把全部的\(\sum\)起来就好了。
代码:

# include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int mod = 1e4+7;
int num[N],col[N];
int s1[N][2],s2[N][2];
int main (){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++) scanf("%d",&num[i]);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d",&col[i]);
		s1[col[i]][i%2]++;
		s2[col[i]][i%2] = (s2[col[i]][i%2]+num[i])%mod;
	}
	long long ans = 0;
	for(int i = 1;i <= n;i++)
	{
		ans += i*(s2[col[i]][i%2]+num[i]*(s1[col[i]][i%2]-2)%mod)%mod;
//		ans = (ans+(i*((s2[col[i]][i%2]-num[i]+mod)%mod+(s1[col[i]][i%2]-1)*num[i]))%mod)%mod;
		ans %= mod;
	}
	cout << ans << endl;
	return 0;
}
posted @ 2025-03-04 22:29  Lunar_Whisper  阅读(2)  评论(0编辑  收藏  举报