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