前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【题解】求和

【题解】求和

作者头像
fishhh
发布2022-08-31 15:02:07
1.2K0
发布2022-08-31 15:02:07
举报
文章被收录于专栏:OI算法学习笔记OI算法学习笔记

题目背景

NOIP2015 普及组 T3

题目描述

一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。每个格子上都染了一种颜色

用[1,m]当中的一个整数表示),并且写了一个数字

img
img

定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:

  1. xyz是整数,x<y<z,y-x=z-y
  2. colorx=colorz

满足上述条件的三元组的分数规定为

。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。

输入格式

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

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

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

输出格式

一个整数,表示所求的纸带分数除以10007所得的余数。

输入输出样例

输入 #1

代码语言:javascript
复制
6 2
5 5 3 2 2 2
2 2 1 1 2 1

输出 #1

代码语言:javascript
复制
82

输入 #2

代码语言:javascript
复制
15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1

输出 #2

代码语言:javascript
复制
1388

说明/提示

【输入输出样例 1 说明】

纸带如题目描述中的图所示。

所有满足条件的三元组为: (1, 3, 5), (4, 5, 6)。

所以纸带的分数为(1+5)×(5+2)+(4+6)×(2+2)=42+40=82

对于第 1 组至第 2 组数据, 1 ≤ n ≤ 100, 1 ≤ m ≤ 5;

对于第3 组至第 4 组数据, 1 ≤ n ≤ 3000, 1 ≤ m ≤ 100;

对于第 5 组至第6组数据, 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000,且不存在出现次数超过2020的颜色;

对 于 全 部 10 组 数 据 , 1≤n≤100000,1≤m≤100000,1≤colori≤m,

题目分析

题目要求的满足条件的三元组的分数和。

三元组需要满足的条件是:

  1. xyz是整数,x<y<z,y-x=z-y
  2. colorx=colorz

那么我们只需要统计每个颜色对应奇偶位置的信息即可。

我们再寻找下计算过程中的相关规律,设序列

为同颜色,位置奇偶性相同的五个元素,我们来算一下相关分数。

再看加起来的总和:

此时可以发现每个元素对总和做出的贡献。

那么可以提前预处理以下同颜色同奇偶位置的元素个数与元素分数和。

定义cnt[x][2] ,第一个下标表示颜色,第二个表示位置奇偶性。定义sum[x][2] ,第一个下标表示颜色,第二个表示位置奇偶性。

预处理部分

代码语言:javascript
复制
for(int i:1~n){
    cin>>color[i];
    cnt[color[i]][i%2]++;//统计个数
    sum[color[i]][i%2]+=score[i];//累加分数
}

代码实现

代码语言:javascript
复制
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int M=1e4+7;
ll color[N],num[N];
ll cnt[N][2];
ll sum[N][2];
//cnt[x][0] 颜色x,位置为偶数的个数 cnt[x][1] 颜色x,位置为奇数的个数
//sum[x][0] 颜色x,位置为偶数的总分 sum[x][1] 颜色x,位置为奇数的总分
//
int n,m;
int main(){
	ll ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&num[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&color[i]);
        cnt[color[i]][i%2]++;
        sum[color[i]][i%2]=(sum[color[i]][i%2]+num[i])%M;
    }
	
	for(int i=1;i<=n;i++){
		int c=color[i];
		ans+=i*((cnt[c][i%2]-1)*num[i]%M+(sum[c][i%2]%M-num[i]%M+M)%M)%M;
		ans%=M;
	}
	printf("%lld",ans);
    return 0;
}

Q.E.D.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目背景
  • 题目描述
  • 输入格式
  • 输出格式
  • 输入输出样例
  • 说明/提示
  • 题目分析
  • 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档