[NOIP2015 普及组] 求和
题目背景
NOIP2015 普及组 T3
题目描述
一条狭长的纸带被均匀划分出了 n n n个格子,格子编号从 1 1 1到 n n n。每个格子上都染了一种颜色 c o l o r i color_i colori用 [ 1 , m ] [1,m] [1,m]当中的一个整数表示),并且写了一个数字 n u m b e r i number_i numberi。
定义一种特殊的三元组: ( x , y , z ) (x,y,z) (x,y,z),其中 x , y , z x,y,z x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
-
x y z xyz xyz是整数, x < y < z , y − x = z − y xx<y<z,y−x=z−y
-
c o l o r x = c o l o r z colorx=colorz colorx=colorz
满足上述条件的三元组的分数规定为 ( x + z ) × ( n u m b e r x + n u m b e r z ) (x+z) \times (number_x+number_z) (x+z)×(numberx+numberz)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以 10 , 007 10,007 10,007所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数 n n n和 m , n m,n m,n表纸带上格子的个数, m m m表纸带上颜色的种类数。
第二行有 n n n用空格隔开的正整数,第 i i i数字 n u m b e r number number表纸带上编号为 i i i格子上面写的数字。
第三行有 n n n用空格隔开的正整数,第 i i i数字 c o l o r color color表纸带上编号为 i i i格子染的颜色。
输出格式
一个整数,表示所求的纸带分数除以 10007 10007 10007所得的余数。
样例 #1
样例输入 #1
6 2
5 5 3 2 2 2
2 2 1 1 2 1
样例输出 #1
82
样例 #2
样例输入 #2
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
1388
提示
【输入输出样例 1 说明】
纸带如题目描述中的图所示。
所有满足条件的三元组为: ( 1 , 3 , 5 ) , ( 4 , 5 , 6 ) (1, 3, 5), (4, 5, 6) (1,3,5),(4,5,6)。
所以纸带的分数为 ( 1 + 5 ) × ( 5 + 2 ) + ( 4 + 6 ) × ( 2 + 2 ) = 42 + 40 = 82 (1 + 5) \times (5 + 2) + (4 + 6) \times (2 + 2) = 42 + 40 = 82 (1+5)×(5+2)+(4+6)×(2+2)=42+40=82。
对于第 1 1 1 组至第 2 2 2 组数据, 1 ≤ n ≤ 100 , 1 ≤ m ≤ 5 1 ≤ n ≤ 100, 1 ≤ m ≤ 5 1≤n≤100,1≤m≤5;
对于第$ 3$ 组至第 4 4 4 组数据, 1 ≤ n ≤ 3000 , 1 ≤ m ≤ 100 1 ≤ n ≤ 3000, 1 ≤ m ≤ 100 1≤n≤3000,1≤m≤100;
对于第 5 5 5 组至第$ 6 $组数据, 1 ≤ n ≤ 100000 , 1 ≤ m ≤ 100000 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000 1≤n≤100000,1≤m≤100000,且不存在出现次数超过$ 20 $的颜色;
对 于 全 部 10 10 10 组 数 据 , 1 ≤ n ≤ 100000 , 1 ≤ m ≤ 100000 , 1 ≤ c o l o r i ≤ m , 1 ≤ n u m b e r i ≤ 100000 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, 1 ≤ color_i ≤ m,1≤number_i≤100000 1≤n≤100000,1≤m≤100000,1≤colori≤m,1≤numberi≤100000
分析:
这哪是前缀和呀这题,这明明是数学,纯纯的数学公式推导SOS
根据这两个条件:
- x y z xyz xyz是整数, x < y < z , y − x = z − y xx<y<z,y−x=z−y
- c o l o r x = c o l o r z colorx=colorz colorx=colorz
可以很清楚的看出来实际上 y y y在这里根本没起作用,只要 x + z = 2 y , c o l o r x = c o l o r z x+z = 2y,colorx = colorz x+z=2y,colorx=colorz就可以了,也就是只要 x , z x,z x,z的奇偶相同,颜色相同就OK。 所以,很自然的就想到可以把奇偶和颜色分开,分别计算。
在此基础上再做优化就是数学推导,三元组规定为 ( x + z ) × ( n u m b e r x + n u m b e r z ) (x+z) \times (number_x+number_z) (x+z)×(numberx+numberz),把式子展开来看就是:
x × n u m b e r x + x × n u m b e r z + z × n u m b e r x + z × n u m b e r z x\times number_x+x\times number_z+z\times number_x+z\times number_z x×numberx+x×numberz+z×numberx+z×numberz
在对颜色和奇偶进行分类后,对我们的每一个集合内的数来分析就有:
( i 1 + i 2 ) × ( n i 1 + n i 2 ) + ( i 1 + i 3 ) × ( n i 1 + n i 3 ) + . . . . . . + ( i 1 + i k ) × ( n i 1 + n i k ) (i_1+i_2)\times (n_{i_1}+n_{i_2}) + (i_1+i_3)\times (n_{i_1}+n_{i_3}) +......+(i_1+i_k)\times (n_{i_1}+n_{i_k}) (i1+i2)×(ni1+ni2)+(i1+i3)×(ni1+ni3)+......+(i1+ik)×(ni1+nik)+ ( i 2 + i 3 ) × ( n i 2 + n i 3 ) + ( i 2 + i 4 ) × ( n i 2 + n i 4 ) + . . . . . . + ( i 2 + i k ) × ( n i 2 + n i k ) (i_2+i_3)\times (n_{i_2}+n_{i_3})+(i_2+i_4)\times (n_{i_2}+n_{i_4})+......+(i_{2}+i_{k})\times (n_{i_2}+n_{i_k}) (i2+i3)×(ni2+ni3)+(i2+i4)×(ni2+ni4)+......+(i2+ik)×(ni2+nik)+…+ ( i k + i k − 1 ) × ( n i k + n i k − 1 ) (i_k+i_{k-1})\times (n_{i_k}+n_{i_{k-1}}) (ik+ik−1)×(nik+nik−1)
然后,把每一个都乘开来看就是这样的:
[ ( i 1 × n i 1 + i 1 × n i 2 + i 2 × n i 1 + i 2 × n i 2 ) + ( i 1 × n i 1 + i 1 × n i 3 + i 3 × n i 1 + i 3 × n i 3 ) + . . . . . . + ( i 1 × n i 1 + i 1 × n i k + i k × n i 1 + i k × n i k ) ] [(i_1\times n_{i_1}+i_1\times n_{i_2}+i_2\times n_{i_1}+i_2\times n_{i_2})+(i_1\times n_{i_1}+i_1\times n_{i_3}+i_3\times n_{i_1}+i_3\times n_{i_3})+......+(i_1\times n_{i_1}+i_1\times n_{i_k}+i_k\times n_{i_1}+i_k\times n_{i_k})] [(i1×ni1+i1×ni2+i2×ni1+i2×ni2)+(i1×ni1+i1×ni3+i3×ni1+i3×ni3)+......+(i1×ni1+i1×nik+ik×ni1+ik×nik)]+ [ ( i 2 × n i 2 + i 2 × n i 3 + i 3 × n i 2 + i 3 × n i 3 ) + ( i 2 × n i 2 + i 2 × n i 4 + i 4 × n i 2 + i 4 × n i 4 ) + . . . . . . + ( i 2 × n i 2 + i 2 × n i k + i k × n i 2 + i k × n i k ) ] [(i_2\times n_{i_2}+i_2\times n_{i_3}+i_3\times n_{i_2}+i_3\times n_{i_3})+(i_2\times n_{i_2}+i_2\times n_{i_4}+i_4\times n_{i_2}+i_4\times n_{i_4})+......+(i_2\times n_{i_2}+i_2\times n_{i_k}+i_k\times n_{i_2}+i_k\times n_{i_k})] [(i2×ni2+i2×ni3+i3×ni2+i3×ni3)+(i2×ni2+i2×ni4+i4×ni2+i4×ni4)+......+(i2×ni2+i2×nik+ik×ni2+ik×nik)]+…+ [ ( i k × n i k + i k × n i k − 1 + i k − 1 × n i k + i k − 1 × n i k − 1 ) ] [(i_k\times n_{i_k}+i_k\times n_{i_{k-1}}+i_{k-1}\times n_{i_k}+i_{k-1}\times n_{i_{k-1}})] [(ik×nik+ik×nik−1+ik−1×nik+ik−1×nik−1)]
然后先只看第一个中括号里面的数,就会发现它是:
( k − 1 ) × ( i 1 × n i 1 ) + i 1 × ∑ t = 2 k n i t + (k-1)\times (i_1\times n_{i_1})+i_1\times\sum_{t=2}^k n_{i_t}+ (k−1)×(i1×ni1)+i1×∑t=2knit+一些其他的内容,动动你聪明的脑瓜和灵巧的小手自己展吧
然后这个 ( k − 1 ) × ( i 1 × n i 1 ) + i 1 × ∑ t = 2 k n i t (k-1)\times (i_1\times n_{i_1})+i_1\times\sum_{t=2}^k n_{i_t} (k−1)×(i1×ni1)+i1×∑t=2knit就可以进一步的写成 ( k − 2 ) × ( i 1 × n i 1 ) + i 1 × ∑ t = 1 k n i t (k-2)\times (i_1\times n_{i_1})+i_1\times\sum_{t=1}^k n_{i_t} (k−2)×(i1×ni1)+i1×∑t=1knit这里我们终于看到了前缀和,感天动地。把后面的内容展开的话就会发现他们最后可以归成一个形式类似的式子也就是
( k − 2 ) × ( i r × n i r ) + i r × ∑ t = 1 k n i t (k-2)\times (i_r\times n_{i_r})+i_r\times\sum_{t=1}^k n_{i_t} (k−2)×(ir×nir)+ir×t=1∑knit
所以我们就可以先处理出前缀和和相同颜色,相同奇偶的数的个数,这样只要O(n)的时间复杂度就可以处理出来所有的结果了。
代码:
#include
using namespace std;
const int N = 100010;
const int mod = 10007;
int n,m;
int idx[N],color[N];
int cnt[N][2];
int sum[N][2];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%d",&idx[i]);
idx[i] = idx[i]%mod;
}
for(int i = 1;i <= n;i++)
{
int c;
scanf("%d",&c);
color[i] = c;
cnt[c][i%2]++;
sum[c][i%2] = (sum[c][i%2]+idx[i])%mod;
}
long long ans = 0;
for(int i = 1;i <= n;i++)
{
int c = color[i];
ans += i*((sum[c][i%2]+((cnt[c][i%2]-2)*idx[i]%mod+mod))%mod)%mod;
ans %= mod;
}
printf("%lld",ans);
return 0;
}