[Noip2015PJ] 求和

本文介绍了一种算法,用于计算一种特殊纸带上的三元组分数之和,并通过模运算求得余数。纸带被均匀划分为n个格子,每个格子含有颜色和数字,算法需找出符合条件的三元组并计算总分数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

一条狭长的纸带被均匀划分出了 \(n\) 个格子,格子编号从 \(1\)\(n\) 。每个格子上都染了一种颜色 \(color_i\)\([1,m]\) 当中的一个整数表示),并且写了一个数字 \(number_i\)

img

定义一种特殊的三元组:\((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\) 所得的余数即可。

Input

第一行是用一个空格隔开的两个正整数 \(n\)\(m\)\(n\) 表纸带上格子的个数, \(m\) 表纸带上颜色的种类数。

第二行有 \(n\) 用空格隔开的正整数,第 \(i\) 数字 \(number\) 表纸带上编号为 \(i\) 格子上面写的数字。

第三行有 \(n\) 用空格隔开的正整数,第 \(i\) 数字 \(color\) 表纸带上编号为 \(i\) 格子染的颜色。

Output

共一行,一个整数,表示所求的纸带分数除以 \(10,007\) 所得的余数。

Hint

对 于 全 部 \(10\) 组 数 据 , \(1\leq n\leq 100000, 1\leq m\leq 100000, 1\leq color_i\leq m,1\leq number_i\leq 100000\)

Solution

首先能够推导出 \(x\)\(z\) 的编号一定是奇偶性相同的。

所以想到对于奇数点和偶数点分开统计答案。

拆一下 \((x,y,z)\) 三元组对答案产生的贡献:\((x+z)\times (number_x+number_z)=x\times number_x+x\times number_z+z\times number_x+z\times number_z\)

观察拆完的式子,发现后边三项中与 \(x\) 无关的项都能用前缀和维护。

比如说第二项中的 \(x\times number_z,number_z\) 显然能用前缀和统计。即扫描到 \(x\) 节点时它和后面某个点 \(z\) 对答案在第二项的贡献即为 \((qzh\_number[z]-qzh\_number[x])\times x\)

所以得到了以下这个基本完成的算法:

对于每个颜色,分别开两个数组,存储奇数节点和偶数节点的编号,记为 \(odd\)\(even\)

对于每个颜色中的 \(even\)\(odd\),再开三个前缀和数组分别维护 \(number_z,z,z\times number_z\) 的和。

然后扫描每个颜色,对每个颜色中存储的每个编号从头到尾扫一遍,答案加上这个点之后的所有点与这个点组成的三元组的贡献即可。

Code

#include<cstdio>
#include<vector>
#include<cctype>
#define N 100005
#define mod 10007
#define int long long

int ans;
int n,m;
int num[N];
int col[N];
bool vis[N];

std::vector<int> even[N],odd[N];
std::vector<int> qzh1[N],qzh2[N],qzh3[N];
std::vector<int> qzh4[N],qzh5[N],qzh6[N];

inline char nc(){
    static const int BS=1<<22;
    static unsigned char buf[BS],*st,*ed;
    if(st==ed) ed=buf+fread(st=buf,1,BS,stdin);
    return st==ed?EOF:*st++;
}
//#define nc getchar
inline int getint(){
    char ch;
    int res=0;
    while(!isdigit(ch=nc()));
    while(isdigit(ch)){
        res=(res<<1)+(res<<3)+(ch^48);
        ch=nc();
    }
    return res;
}

signed main(){
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)
        num[i]=getint();
    for(int i=1;i<=n;i++){
        col[i]=getint();
        if(i&1){
            odd[col[i]].push_back(i);
            int a=qzh1[col[i]].size();
            if(!qzh1[col[i]].empty())
                qzh1[col[i]].push_back((qzh1[col[i]][a-1]+num[i]));
            else qzh1[col[i]].push_back(num[i]);
            a=qzh2[col[i]].size();
            if(!qzh2[col[i]].empty())
                qzh2[col[i]].push_back((qzh2[col[i]][a-1]+i));
            else qzh2[col[i]].push_back(i);
            a=qzh3[col[i]].size();
            if(!qzh3[col[i]].empty())
                qzh3[col[i]].push_back((qzh3[col[i]][a-1]+i*num[i]));
            else qzh3[col[i]].push_back((i*num[i]));
        }
        else{
            even[col[i]].push_back(i);
            if(!qzh4[col[i]].empty())
                qzh4[col[i]].push_back((qzh4[col[i]][qzh4[col[i]].size()-1]+num[i]));
            else qzh4[col[i]].push_back(num[i]);
            if(!qzh5[col[i]].empty())
                qzh5[col[i]].push_back((qzh5[col[i]][qzh5[col[i]].size()-1]+i));
            else qzh5[col[i]].push_back(i);
            if(!qzh6[col[i]].empty())
                qzh6[col[i]].push_back((qzh6[col[i]][qzh6[col[i]].size()-1]+i*num[i]));
            else qzh6[col[i]].push_back((i*num[i]));
        }
    }
    for(int k=1;k<=n;k++){
        if(vis[col[k]]) continue;
        vis[col[k]]=1;
        for(int i=0;i<odd[col[k]].size();i++){
            int p=odd[col[k]].size()-i-1;
            (ans+=odd[col[k]][i]%mod*num[odd[col[k]][i]]%mod*p%mod)%=mod;
            (ans+=odd[col[k]][i]%mod*(qzh1[col[k]][qzh1[col[k]].size()-1]-qzh1[col[k]][i])%mod)%=mod;
            (ans+=num[odd[col[k]][i]]%mod*(qzh2[col[k]][qzh2[col[k]].size()-1]-qzh2[col[k]][i])%mod)%=mod;
            (ans+=qzh3[col[k]][qzh3[col[k]].size()-1]-qzh3[col[k]][i])%=mod;
        }
        for(int i=0;i<even[col[k]].size();i++){
            int p=even[col[k]].size()-i-1;
            (ans+=even[col[k]][i]%mod*num[even[col[k]][i]]%mod*p%mod)%=mod;
            (ans+=even[col[k]][i]%mod*(qzh4[col[k]][qzh4[col[k]].size()-1]-qzh4[col[k]][i])%mod)%=mod;
            (ans+=num[even[col[k]][i]]%mod*(qzh5[col[k]][qzh5[col[k]].size()-1]-qzh5[col[k]][i])%mod)%=mod;
            (ans+=qzh6[col[k]][qzh6[col[k]].size()-1]-qzh6[col[k]][i])%=mod;
        }
    }
    printf("%lld\n",ans%mod);
    return 0;
}

转载于:https://www.cnblogs.com/YoungNeal/p/9088638.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值