P2671 [NOIP2015 普及组] 求和(前缀和)

简介: P2671 [NOIP2015 普及组] 求和(前缀和)

1.描述:


一条狭长的纸带被均匀划分出了nn个格子,格子编号从11到nn。每个格子上都染了一种颜色c o l o r 用[1,m]当中的一个整数表示),并且写了一个数字n u m b e r

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

fefade5cc938f2bb5b3faff6d8979962_bdbe1703346349aa8719d3fd1f1bc3aa.png


1.xyz是整数 x

2.color x = color z


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

image.png

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


2. 输入:


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

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

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

f3096a334fdda82354b8ca17cdb1899c_f96dd08c9dea46afba0fba5ecee91938.png


3.输出:


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


4.样例输入:


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


5.样例输出:


1388


6.题目大意:


找所有满足关系的三元对 的 贡献和


7.思路


80分思路:


所有的三元对与中间元素没什么关系,只要首尾元素满足同奇或同偶且颜色相同即可组对,把所有满足条件元素输入便输入边处理即可


80分代码 O( n*n )


最多 1e5 种颜色 , 同种颜色 i 奇数 放在 i * 2 - 1,偶数放在 i * 2

#include<bits/stdc++.h>
using namespace std;
//ios::sync_with_stdio(false);
const int N = 1e6+10; 
typedef long long ll;
int n,m;
struct node{
  ll num;
  ll n; 
  ll col;
}a[N];
const int p = 1e4+7;
vector<node>ve[N];
ll sum;
int main()
{
  ios::sync_with_stdio(false);
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
    a[i].n=i;
    cin>>a[i].num;
  }
  for(int i=1;i<=n;i++)
  {
    cin>>a[i].col;
    if(a[i].n%2!=0)
    {
      ve[2*a[i].col-1].push_back(a[i]);
      int s=2*a[i].col-1;
      int t=ve[s].size()-1;
      for(int j=0;j<t;j++)
      {
        sum=(sum+((ve[s][j].n+ve[s][t].n)*(ve[s][j].num+ve[s][t].num)))%p;  
      }
    }
    else
    {
      ve[2*a[i].col].push_back(a[i]);
      int s=2*a[i].col;
      int t=ve[s].size()-1;
      for(int j=0;j<t;j++)
      {
        sum=(sum+((ve[s][j].n+ve[s][t].n)*(ve[s][j].num+ve[s][t].num)))%p;  
      }
    }
  }
  cout<<sum;
}


复杂度 O( n2 ) 1e10,爆了


100分思路:O( n )


image.png

化简

image.png

那么不难发现,可以维护的东西出来了(有些东西是可以维护累加和(前缀和)的),对于每种颜色的不同奇偶,我们可以维护一个

image.png

对应式子第一列

维护一个s u m x 数 组

对应式子第二列的 x的和

维护一个 s u m n 数 组

对应式子第三列的image.png的和

维护一个c n t 数 组

对应第四列image.png的个数


一百分代码


#include<bits/stdc++.h>
using namespace std;
//ios::sync_with_stdio(false);
const int N = 3*1e5+10; 
typedef  long long ll;
int n,m;
ll num[N],col;
const int p = 10007;
ll sumx[N];
ll sumn[N];
ll sumxn[N];
ll cnt[N];
ll sum;
int main()
{
  ios::sync_with_stdio(false);
  cin>>n>>m;
  for(int i=1;i<=n;i++)  cin>>num[i];
  for(int i=1;i<=n;i++)
  {
    cin>>col;   
    if(i%2!=0)
    {
      int s=col*2-1;
      sum=(sum+sumxn[s]%p+sumx[s]*num[i]%p+sumn[s]*i%p+i*num[i]*cnt[s]%p)%p;
      sumxn[s]=(sumxn[s]+i*num[i])%p;
      sumx[s]=(sumx[s]+i)%p;
      sumn[s]=(sumn[s]+num[i])%p;
      cnt[s]++;
    }
    else
    {
      int s=col*2;
      sum=(sum+sumxn[s]%p+sumx[s]*num[i]%p+sumn[s]*i%p+i*num[i]*cnt[s]%p)%p;
      sumxn[s]=(sumxn[s]+i*num[i])%p;
      sumx[s]=(sumx[s]+i)%p;
      sumn[s]=(sumn[s]+num[i])%p;
      cnt[s]++;
    }
  }
  cout<<sum;
}


8.反思


一开始想出来第二种思路了,没开 long long 调了好久,还把思路又想了好几遍,没开 long long 只有四十分,从八十分到四十分,人傻了,纯纯nt,以后累加要取余的题一定要注意

1.开 long long

2.不断地 %%%%(进行取余)

3.可以用 ios::sync_with_stdio(false) 来加速,前缀和非常好的一道题


最后的最后,觉得写的还不错的,一定要点个赞留个言支持一下~~~


目录
相关文章
【2001NOIP普及组】T3. 求先序排列 试题解析
【2001NOIP普及组】T3. 求先序排列 试题解析
|
6月前
|
C++
【洛谷 P1307】[NOIP2011 普及组] 数字反转 题解(字符串)
**NOIP2011普及组题目:给定整数N,反转其位得到新数。新数首位非0(除非N=0)。输入0时直接输出0,其他情况输出反转后的数,考虑负数及前导0。提供的C++代码实现通过读入字符串,反转数字顺序并处理符号和前导0。**
38 0
|
6月前
【洛谷 P1307】[NOIP2011 普及组] 数字反转 题解(取余)
NOIP2011普及组试题,要求反转整数N的位得到新数,保持正负号和非零最高位。输入一个整数N,输出反转后的新数。样例输入1:123,输出:321;样例输入2:-380,输出:-83。代码使用取余法实现,处理负数时保留符号。
61 0
|
5月前
【洛谷】P1308 [NOIP2011 普及组] 统计单词数
然后要被查找的b字符串,可能会出现第二个样例中的情况,也就是字符串a是to,而字符串b的Ottoman,这样是不符合题意的。为了 解决这个问题,我们将字符串a首尾都加一个空格,同时将字符串b首尾都加一个空格(这里是为了让字符串b的首单词和尾单词前后均有空格)为了能持续找字符串b中的所有字符串a,我们用一个while循环,如果能找到,就每次从能找到的位置的下一个位置(也就是能找到的位置下标+1)开始找,并及时更新位置,同时计数。因为不区分大小写,所以可以将两个字符串a,b都转为小写(也可以都转为大写)。
158 10
【洛谷】P1308 [NOIP2011 普及组] 统计单词数
|
6月前
【洛谷 P1035】[NOIP2002 普及组] 级数求和 题解(循环)
**NOIP2002普及组题目:求级数$S_n=1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n}$超过$k$的最小$n$。给定$1\leq k\leq 15$,输出满足$S_n&gt;k$的$n$。输入$1$个整数$k$,输出相应$n$。例如,输入$1$,输出$2$。代码中使用double确保精度,通过累加求和判断条件找到$n$。**
47 0
|
6月前
|
机器学习/深度学习 存储
【洛谷 P1028】[NOIP2001 普及组] 数的计算 题解(递归)
**NOIP2001普及组数的计算**:给定自然数\( n \),构造数列,新数不超过序列最后一项一半。求合法数列个数。输入\( n \)(\(1 \leq n \leq 10^3\))。样例:输入6,输出6。递归解决,代码中定义函数`f`实现递归计算,总和存储在`cnt`中,最后输出。
61 0
|
6月前
|
机器学习/深度学习 人工智能
【洛谷 P1028】[NOIP2001 普及组] 数的计算 题解(递推)
在NOIP2001普及组的数的计算题目中,给定自然数`n`,需构造遵循特定规则的合法数列。合法序列始于`n`,新元素不超过前一项的一半。任务是找出所有这样的数列数量。例如,当`n=6`时,合法序列包括`6`, `6,1`, `6,2`, `6,3`, `6,2,1`, `6,3,1`。程序通过动态规划求解,当`i`为奇数时,`a[i] = a[i - 1]`;为偶数时,`a[i] = a[i - 1] + a[i / 2]`。代码中预处理数组`a`并输出`a[n]`作为答案。输入`n`后,程序直接计算并打印合法数列个数。
79 0
|
6月前
【洛谷 P1036】[NOIP2002 普及组] 选数 题解(深度优先搜索+判断质数+枚举子集)
**NOIP2002普及组选数问题**:给定$n$个整数和一个整数$k$,需找出所有$k$个数的组合,计算它们的和为素数的种类数。输入包含$n$和$k$,以及$n$个整数;输出是符合条件的组合数。例如,对于输入`4 3`和数组`[3, 7, 12, 19]`,输出为`1`。代码使用递归枚举子集并检查质数的方法。
100 0
|
6月前
【洛谷 P1088】[NOIP2004 普及组] 火星人 题解(全排列+向量)
**火星人问题摘要:** NOIP2004普及组竞赛中的题目,涉及火星人用手指的排列表示数字。人类需计算火星人数字与给定数值之和的新排列。给定火星人手指数N(≤10000),加上的数M(≤100),以及初始排列,要求输出新排列。30%的数据中N≤15,60%的数据中N≤50。使用`next_permutation`函数找到第M个排列。样例:N=5, M=3, 初始排列1 2 3 4 5,输出1 2 4 5 3。
72 0
|
7月前
P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
41 0