题目链接:
思路:
洛谷将这道题放到差分前缀和专题中,但我觉得这个知识点在这道题中并没有很大的体现。
核心:分组!
分组条件:
根据:奇数+奇数=偶数 ,偶数+偶数=偶数,所以符合条件的x和z一定都是奇数或者都是偶数。再根据颜色分组。下面代码用a[c][j]表示分组的结果,其中c表示颜色种类,j表示奇偶情况。
所以最终只有一个组内的元素,两两之间符合限定条件,那么现在问题便转化为如何计算一个组内所有元素两两匹配,构成的(x+z)*(Numx+Numz)。
这里先假设一个组内有3个元素x1,x2,x3,此时再插入一个元素z,ans会增加多少?
计算得,增加:
观察可得,只需记录前3项的四个值便可快速计算出新增1个元素ans增加的值。
四个值分别为:
以及这个组中元素的个数cnt
易得,新增一个元素z,ans增加的值为
问题解决,编写代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
const int MOD = 10007;
struct cj
{
ll sum_xi;
ll sum_num_xi;
ll sum_xi_num_xi;
ll cnt;
};
cj a[MAXN][2];
ll ans=0;
ll color[MAXN],num[MAXN];
ll n,m;
ll c,j;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>num[i];
for(int i=1;i<=n;++i) cin>>color[i];
for(int i=1;i<=n;++i)
{
c=color[i];
j=i%2;
ans+=a[c][j].sum_xi_num_xi+a[c][j].cnt*i*num[i]+a[c][j].sum_xi*num[i]+i*a[c][j].sum_num_xi;
ans%=MOD;
a[c][j].cnt++;
a[c][j].sum_xi=(i+a[c][j].sum_xi)%MOD;
a[c][j].sum_num_xi=(num[i]+a[c][j].sum_num_xi)%MOD;
a[c][j].sum_xi_num_xi=(a[c][j].sum_xi_num_xi+i*num[i])%MOD;
}
cout<<ans<<endl;
return 0;
}