前缀和:洛谷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;
}

 

posted @ 2021-11-08 23:47  遥望未来weilai  阅读(56)  评论(0)    收藏  举报