题意:一条狭长的纸带被均匀划分出了(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;
}