求和

洛咕

题意:一条狭长的纸带被均匀划分出了\(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) \times (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\n",ans);
    return 0;
}

posted on 2019-10-04 17:23  PPXppx  阅读(201)  评论(0编辑  收藏  举报