求和

洛咕

题意:一条狭长的纸带被均匀划分出了(n)个格子,格子编号从(1)(n)。每个格子上都染了一种颜色(color\_i)([1,m])当中的一个整数表示),并且写了一个数字(number\_i)

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

1. (x,y,z)是整数,(x<y<z,y-x=z-y)

2. (color_x=color_z)

满足上述条件的三元组的分数规定为((x+z) imes (number\_x+number\_z)),整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以(10,007)所得的余数即可,(n,m<=100000).

分析:首先想了个(n*m)的做法看能不能水过去,只有(60)分,就是枚举位置(i)作为右端点(z)能够产生的贡献,前面扫的时候用一个(vector)记下每种颜色出现的位置,如果前面的位置加上当前位置i是个偶数,就可以计算贡献了.

前面那种算法对于一些颜色重复计算了多次,我们考虑(i,j,k)三者两两之间都能够产生贡献,则产生的总贡献为((i+j)*(val[i]+val[j])+(i+k)*(val[i]+val[k])+(j+k)*(val[j]+val[k])),整理一下这个式子可以得到(2*(i*val[i]+j*val[j]+k*val[k])+i*(val[j]+val[k])+j*(val[i]+val[k])+k*(val[i]+val[j])).

这个计算式子是有规律的.然后考虑(i,j,k)需要满足什么条件才能两两之间都能产生贡献呢?颜色相同,奇偶性相同.

所以我们预处理(vector)数组,(q[i][0/1][j])表示第i种颜色,位置是偶数/奇数的 第j个的 位置.同时处理出(sum[i][0/1])表示第i种颜色,位置是偶数/奇数的 分数之和.

然后就可以直接枚举每种颜色然后计算贡献了.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int mod=10007;
const int N=100005;
int val[N],num[N];
ll sum[N][2];
vector<int>q[N][2];
int main(){
	int n=read(),m=read();ll ans=0;
	for(int i=1;i<=n;++i)val[i]=read();
	for(int i=1;i<=n;++i)num[i]=read();
	for(int i=1;i<=n;++i){
		if(i&1){
			q[num[i]][1].push_back(i);
			sum[num[i]][1]+=val[i];
		}
		else{
			q[num[i]][0].push_back(i);
			sum[num[i]][0]+=val[i];
		}
	}
	for(int i=1;i<=m;++i){
		int tot=q[i][0].size()-1;
		for(int j=0;j<=tot;++j){
			ans=(ans+1ll*tot*q[i][0][j]*val[q[i][0][j]]%mod)%mod;
			ans=(ans+1ll*q[i][0][j]*(sum[i][0]-val[q[i][0][j]])%mod)%mod;
		}
		tot=q[i][1].size()-1;
		for(int j=0;j<=tot;++j){
			ans=(ans+1ll*tot*q[i][1][j]*val[q[i][1][j]]%mod)%mod;
			ans=(ans+1ll*q[i][1][j]*(sum[i][1]-val[q[i][1][j]])%mod)%mod;
		}
	}
	/*for(int i=1;i<=n;++i){
		for(int j=0;j<q[num[i]].size();++j){
			if((i+q[num[i]][j])&1)continue;
			ans=(ans+1ll*(i+q[num[i]][j])*(val[i]+val[q[num[i]][j]])%mod)%mod;
		}
		q[num[i]].push_back(i);	
	}*///n*m的做法
	printf("%lld
",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11622598.html