前缀和:洛谷P2671 [NOIP2015 普及组] 求和
因为三元组x,y,z是等差数列,所以x和z奇偶性一致,然后按照奇偶以及颜色分组
对于某种奇偶性的某种颜色:
答案=(x[1]+x[2])*(y[1]+y[2])+(x[1]+x[3])*(y[1]+y[3])+……+(x[1]+x[k])*(y[1]+y[k])
+(x[2]+x[3])*(y[2]+y[3])+(x[2]+x[4])*(y[2]+y[4])+……+(x[2]+x[k])*(y[2]+y[k])
+......+(x[k-1]+x[k])\*(y[k-1]+y[k])
xk和每个yi乘了一遍,跟yk额外乘了k-2遍
然后就是O(n)的前缀和了,先求出Σy即可
#include<bits/stdc++.h> #define N 100005 #define mod 10007 using namespace std; long long a[N],b[N],osum[N],esum[N]; vector<int> odd[N],even[N]; vector<int> oddn[N],evenn[N]; int main(){ long long n,m,i,j,x,ans; cin>>n>>m; for(i=1;i<=n;i++){ // scanf("%lld",&a[i]); cin>>a[i]; } for(i=1;i<=n;i++){ cin>>x; // scanf("%lld",&x); if(i%2==1){ odd[x].push_back(a[i]); oddn[x].push_back(i); } else{ even[x].push_back(a[i]); evenn[x].push_back(i); } } for(i=1;i<=m;i++){ osum[i]=0; for(j=0;j<odd[i].size();j++){ // printf("%d %d\n",odd[i][j],oddn[i][j]); osum[i]+=odd[i][j]; osum[i]%=mod; } // printf("---%d\n",osum[i]); esum[i]=0; for(j=0;j<even[i].size();j++){ // printf("%d %d\n",even[i][j],evenn[i][j]); esum[i]+=even[i][j]; esum[i]%=mod; } // printf("---%d\n",esum[i]); } ans=0; for(i=1;i<=m;i++){ if(odd[i].size()>=2) for(j=0;j<odd[i].size();j++){ // cout<<oddn[i][j]<<"*"<<(osum[i]+(n-2)*odd[i][j])<<endl; ans+=(oddn[i][j]*(osum[i]+(odd[i].size()-2)*odd[i][j])); ans%=mod; } if(even[i].size()>=2) for(j=0;j<even[i].size();j++){ ans+=(evenn[i][j]*(esum[i]+(even[i].size()-2)*even[i][j])); ans%=mod; } } cout<<ans; }

浙公网安备 33010602011771号