NOIP2015普及组复赛T3——求和

题目描述

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

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

  • x , y , z x,y,z x,y,z都是整数, x < y < z , y − x = z − y x < y < z, y − x = z − y x<y<z,yx=zy
  • c o l o r x = c o l o r z color_x=color_z colorx=colorz

满足上述条件的三元组的分数规定为 ( x + z ) ∗ ( n u m b e r x + n u m b e r z ) (x+z)∗(number_x+number_z) (x+z)(numberx+numberz)

整个纸带的分数规定为所有满足条件的三元组的分数的和。

这个分数可能会很大,你只要输出整个纸带的分数除以 10007 10007 10007 所得的余数即可。

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

第二行有 n n n 个用空格隔开的正整数,第 i i i 个数字 n u m b e r i number_i numberi代表纸带上编号为 i i i 的格子上面写的数字。

第三行有 n n n 个用空格隔开的正整数,第 i i i 个数字 c o l o r i color_i colori代表纸带上编号为 i i i 的格子染的颜色。

输出格式
共一行,一个整数,表示所求的纸带分数除以 10007 10007 10007 所得的余数。

数据范围
1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^5 1n,m105,
1 ≤ n u m b e r i ≤ 105 1≤number_i≤105 1numberi105,
1 ≤ c o l o r i ≤ m 1≤color_i≤m 1colorim

输入样例:

6 2
5 5 3 2 2 2
2 2 1 1 2 1

输出样例:

82


算法1

(暴力枚举) 40分 O ( n 2 ) O(n^2) O(n2)

三元组:(x, y, z)要求满足以下两个条件:

  • x , y , z x,y,z x,y,z都是整数, x < y < z , y − x = z − y x < y < z, y − x = z − y x<y<z,yx=zy
  • c o l o r x = c o l o r z color_x=color_z colorx=colorz

那么: x + = 2 y x + = 2y x+=2y。由此可以枚举 x x x y y y的值,如果颜色相同,累加分值即可。

时间复杂度

O ( n 2 ) O(n^2) O(n2)

C++ 代码

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010, mod = 10007;

int a[N], b[N];

int main()
{
    
    
    int n, m;
    
    scanf("%d%d", &n, &m);
    
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for(int i = 1; i <= n; i ++) scanf("%d", &b[i]);
    
    int ans = 0;
    for(int x = 1; x <= n; x ++)
    {
    
    
        for(int y = x + 1; 2 * y - x <= n; y ++)
        {
    
    
            if(b[x] == b[2 * y - x])
            {
    
    
                ans = (ans + (2 * y) % mod * (a[x] + a[2 * y - x]) % mod) % mod;
            }
        }
    }
    
    printf("%d\n", ans);
    
    return 0;
}

算法2

(数学知识、前缀和) O ( n ) O(n) O(n)

z − x = 2 y z - x = 2y zx=2y为偶数,可以推导出 x , z x,z x,z的奇偶性相同。也就是说,只要满足下列性质就可以产生得分:

  • x < z x < z x<z
  • x x x z z z的颜色相同
  • x x x z z z的奇偶性相同

那么可以将输入数据根据颜色和编号的奇偶性进行分组。把每个颜色分为一组、将每个颜色中再按照奇偶性分组,一共有 m × 2 m\times2 m×2组。累加相同分组内的得分就是最终答案。

不妨设一个分组里有 n n n个格子, x i x_i xi表示格子的编号, w i w_i wi表示格子上的数字。那么这个分组的得分:

a n s = ( x 1 + x 2 ) ( w 1 + w 2 ) + ( x 1 + x 3 ) ( w 1 + w 3 ) + . . . + ( x 1 + x n ) ( w 1 + w n ) ans = (x_1+x_2)(w_1+w_2)+(x_1+x_3)(w_1+w_3)+...+(x_1+x_n)(w_1+w_n) ans=(x1+x2)(w1+w2)+(x1+x3)(w1+w3)+...+(x1+xn)(w1+wn)
+ ( x 2 + x 3 ) ( w 2 + w 3 ) + ( x 2 + x 4 ) ( w 2 + w 4 ) + . . . + ( x 2 + x n ) ( w 2 + w n ) +(x_2+x_3)(w_2+w_3)+(x_2+x_4)(w_2+w_4)+...+(x_2+x_n)(w_2+w_n) +(x2+x3)(w2+w3)+(x2+x4)(w2+w4)+...+(x2+xn)(w2+wn)
+ ( x 3 + x 4 ) ( w 3 + w 4 ) + . . . + ( x 3 + x n ) ( w 3 + w n ) +(x_3+x_4)(w_3+w_4)+...+(x_3+x_n)(w_3+w_n) +(x3+x4)(w3+w4)+...+(x3+xn)(w3+wn)
+ . . . +... +...
+ ( x n − 1 + x n ) ( w n − 1 + w n ) +(x_{n-1}+x_n)(w_{n-1}+w_n) +(xn1+xn)(wn1+wn)

按照格子的编号 x i x_i xi合并同类项:
a n s = x 1 [ ( w 1 + w 2 ) + ( w 1 + w 3 ) + ( w 1 + w 4 ) . . . + ( w 1 + w n ) ] ans=x_1[(w_1+w_2)+(w_1+w_3)+(w_1+w_4)...+(w_1+w_n)] ans=x1[(w1+w2)+(w1+w3)+(w1+w4)...+(w1+wn)]
+ x 2 [ ( w 1 + w 2 ) + ( w 2 + w 3 ) + ( w 2 + w 4 ) + . . . + ( w 2 + w n ) ] +x_2[(w_1+w_2)+(w_2+w_3)+(w_2+w_4)+...+(w_2+w_n)] +x2[(w1+w2)+(w2+w3)+(w2+w4)+...+(w2+wn)]
+ x 3 [ ( w 1 + w 3 ) + ( w 2 + w 3 ) + ( w 3 + w 4 ) + . . . + ( w 3 + w n ) ] +x_3[(w_1+w_3)+(w_2+w_3)+(w_3+w_4)+...+(w_3+w_n)] +x3[(w1+w3)+(w2+w3)+(w3+w4)+...+(w3+wn)]
+ . . . +... +...
+ x n [ ( w 1 + w n ) + ( w 2 + w n ) + ( w 3 + w n ) + . . . + ( w n − 1 + w n ) ] +x_n[(w_1+w_n)+(w_2+w_n)+(w_3+w_n)+...+(w_{n-1}+w_n)] +xn[(w1+wn)+(w2+wn)+(w3+wn)+...+(wn1+wn)]

= x 1 [ ( n − 1 ) w 1 + w 2 + w 3 + w 4 + . . . + w n ] =x_1[(n-1)w_1 + w_2+w_3+w_4+...+w_n] =x1[(n1)w1+w2+w3+w4+...+wn]
+ x 2 [ ( n − 1 ) w 2 + w 1 + w 3 + w 4 + . . . + w n ] +x_2[(n-1)w_2+w_1+w_3+w_4+...+w_n] +x2[(n1)w2+w1+w3+w4+...+wn]
+ x 3 [ ( n − 1 ) w 3 + w 1 + w 4 + w 5 + . . . + w n ] +x_3[(n-1)w_3+w_1+w_4+w_5+...+w_n] +x3[(n1)w3+w1+w4+w5+...+wn]
+ . . . +... +...
+ x n [ ( n − 1 ) w n + w 1 + w 2 + w 3 + . . . + w n − 1 ] +x_n[(n-1)w_n+w_1+w_2+w_3+...+w_{n-1}] +xn[(n1)wn+w1+w2+w3+...+wn1]

整理为:
a n s = x 1 [ ( n − 2 ) w 1 + ( w 1 + w 2 + w 3 + . . . + w n ) ] ans=x_1[(n-2)w_1+(w_1+w_2+w_3+...+w_n)] ans=x1[(n2)w1+(w1+w2+w3+...+wn)]
+ x 2 [ ( n − 2 ) w 2 + ( w 1 + w 2 + w 3 + . . . + w n ) ] +x_2[(n-2)w_2+(w_1+w_2+w_3+...+w_n)] +x2[(n2)w2+(w1+w2+w3+...+wn)]
+ x 3 [ ( n − 2 ) w 3 + ( w 1 + w 2 + w 3 + . . . + w n ) ] +x_3[(n-2)w_3+(w_1+w_2+w_3+...+w_n)] +x3[(n2)w3+(w1+w2+w3+...+wn)]
+ . . . +... +...
+ x n [ ( n − 2 ) w n + ( w 1 + w 2 + . . . + w n ) +x_{n}[(n-2)w_n+(w_1+w_2+...+w_n) +xn[(n2)wn+(w1+w2+...+wn)

即:
a n s = x 1 [ ( n − 2 ) w 1 + ∑ w i ] + x 2 [ ( n − 2 ) w 2 + ∑ w i ] + . . . + x n [ ( n − 2 ) w n + ∑ w i ] ans=x_1[(n-2)w_1+\sum w_i]+x_2[(n-2)w_2+\sum w_i]+...+x_n[(n-2)w_n+\sum w_i] ans=x1[(n2)w1+wi]+x2[(n2)w2+wi]+...+xn[(n2)wn+wi]

提取公因式:
a n s = ( n − 2 ) ( x 1 w 1 + x 2 w 2 + . . . + x n w n ) + ( x 1 + x 2 + . . . + x n ) ∑ w i ans=(n-2)(x_1w_1+x_2w_2+...+x_nw_n)+(x_1+x_2+...+x_n)\sum w_i ans=(n2)(x1w1+x2w2+...+xnwn)+(x1+x2+...+xn)wi

整理得:
a n s = ( n − 2 ) ∑ ( x i w i ) + ∑ x i ∑ w i ans=(n-2)\sum (x_iw_i)+\sum x_i \sum w_i ans=(n2)(xiwi)+xiwi

其中 ( n − 2 ) (n-2) (n2)表示该分组中格子的数量,可以通过前缀和的思想统计出来; x i x_i xi表示第 i i i个格子的编号; ∑ w i \sum w_i wi表示分组中前 i i i个格子的分数和,可同通过前缀和进行计算。

时间复杂度

O ( n ) O(n) O(n)

C++ 代码

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010, mod = 10007;

//w[i]表示第i个格子的数字
//color[i]表示第i个格子的颜色
int w[N], color[N];
//sum[i][0]表示颜色为i、编号为偶数的格子上数字的前缀和
//cnt[i][0]表示颜色为i、编号为偶数的格子的个数
int sum[N][2], cnt[N][2];

int main()
{
    
    
    int n, m;
    
    scanf("%d%d", &n, &m);
    
    for(int i = 1; i <= n; i ++) scanf("%d", &w[i]);
    for(int i = 1; i <= n; i ++) 
    {
    
    
        scanf("%d", &color[i]);
        
        //累加分组内数字和
        sum[color[i]][i % 2] = (sum[color[i]][i % 2] + w[i]) % mod;
        //统计分组内格子个数
        cnt[color[i]][i % 2] ++;
    }
    
    int ans = 0;
    for(int i = 1; i <= n; i ++)
    {
    
    
        ans = (ans +  i * ((cnt[color[i]][i % 2] - 2) * w[i] % mod + sum[color[i]][i % 2])) % mod; 
    }
    
    printf("%d\n", ans);
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qiaoxinwei/article/details/108879281