题目
题目描述
一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。每个格子上都染了一种颜色color_i用[1,m]当中的一个整数表示),并且写了一个数字number_i。
定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下几个条件:
- x,y,z是整数
- x < y < z
- y-x = z-y
- color_x=color_z
满足上述条件的三元组的分数规定为(x+z)*(number_x+number_z)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。
输入
第一行是用一个空格隔开的两个正整数n和m,n表示纸带上格子的个数,m表纸带上颜色的种类数。
第二行有n用空格隔开的正整数,第i数字number表示纸带上编号为i格子上面写的数字。
第三行有n用空格隔开的正整数,第i数字color表示纸带上编号为i格子染的颜色。
输出
共一行,一个整数,表示所求的纸带分数除以10,007所得的余数。
输入样例#1
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输出样例#1
82
输入样例#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 + 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,且不存在出现次数
超过 20 的颜色;
对 于 全 部 10 组 数 据 , 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, 1 ≤ color_i ≤ m,1≤number_i≤100000
思路
概述
看到这道题,我不由自主地想到了2016年的魔法阵= =
它的条件肯定是有心机的,所以一条一条地看:
- x,y,z是整数
这个没什么好说的。 - x < y < z
这个也没什么好说的。 - y-x = z-y
移项,得 z+x=2y ,
2y 为偶数, z+x 等于一个偶数, z 和x 又都为整数,说明 x 和z 同奇同偶。 - color_x=color_z
x 和z 颜色一样。
好像并没有分析出什么,还发现y没有什么用……
但是,对于1-N所有的编号,只要这个编号满足这样的条件,都可以作为一个三元组,所以完全可以把满足上述条件的编号存在一起(暂且先存编号,接下来的推导会让你发现不需要存编号),即是把同奇偶,同颜色的存在一起。
至于y,直接扔掉。
别忘了还有传说中分数的计算方式:
- (x+z)×(numberx+numberz)
把
numberx
简写为
nx
,果断拆开它:
x⋅nx+x⋅nz+z⋅nx+z⋅nz
推导
几个好像看不出什么规律,我们可以多写几个:
设
N
个编号
则总分数为:
(a1+a2)(n1+n2)+(a1+a3)(n1+n3)+(a1+a4)(n1+n4)+...+(a1+aN)(n1+nN)+
(a2+a3)(n2+n3)+(a2+a4)(n2+n4)+(a2+a5)(n2+n5)+...+(a2+aN)(n2+nN)+
(a3+a4)(n3+n4)+(a3+a5)(n3+n5)+(a3+a6)(n3+n6)...+(a3+aN)(n3+nN)+
......+
(aN−2+aN−1)(nN−2+nN−1)+(aN−2+aN)(nN−2+nN)+
(aN−1+aN)(nN−1+nN)
拆开并化简一些得:
(N−1)a1n1+(N−2)a2n2+...+2aN−2nN−2+aN−1nN−1+
a1(n2+n3+...+nN)+a2(n3+n4+...+nN)+...+aN−2(nN−1+nN)+aN−1nN+
n1(a2+a3+...+aN)+n2(a3+a4+...+aN)+...+nN−2(aN−1+aN)+nN−1aN+
a2n2+2a3n3+...+(N−3)aN−2nN−2+(N−2)aN−1nN−1+(N−1)aNnN
这是将每个2次式拆开,然后合并之前
x⋅nx+x⋅nz+z⋅nx+z⋅nz
中相同位置的项后得到的,例如第一行为所有的
x⋅nx
这一项合并后得到的。
将第1行和第4行合并得:
(N−1)a1n1+(N−1)a2n2+...+(N−1)aN−2nN−2+(N−1)aN−1nN−1+(N−1)aNnN+
a1(n2+n3+...+nN)+a2(n3+n4+...+nN)+...+aN−2(nN−1+nN)+aN−1nN+
n1(a2+a3+...+aN)+n2(a3+a4+...+aN)+...+nN−2(aN−1+aN)+nN−1aN
继续:
(N−1)(a1n1+a2n2+...+aN−2nN−2+aN−1nN−1+aNnN)+
a1(n2+n3+...+nN)+a2(n3+n4+...+nN)+...+aN−2(nN−1+nN)+aN−1nN+
n1(a2+a3+...+aN)+n2(a3+a4+...+aN)+...+nN−2(aN−1+aN)+nN−1aN
事实上,最后一行换一种合并方式,提
a
而不提
(N−1)(a1n1+a2n2+...+aN−2nN−2+aN−1nN−1+aNnN)+
a1(n2+n3+...+nN)+a2(n3+n4+...+nN)+...+aN−2(nN−1+nN)+aN−1nN+
a2n1+a3(n1+n2)+...+aN−2(n1+n2+...+nN−3)+aN−1(n1+n2+...+nN−2)+aN(n1+n2+...+nN−1)
于是,2、3行便可以合并了:
(N−1)(a1n1+a2n2+...+aN−2nN−2+aN−1nN−1+aNnN)+
a1(n2+n3+...+nN)+a2(n1+n3+n4+...+nN)+...+aN−1(n1+n2+...+nN−2+nN)+aN(n1+n2+...+nN−1)
发现第二行中的第
i
项中少一个
(N−2)(a1n1+a2n2+...+aN−1nN−1+aNnN)+(a1+a2+...+aN)(n1+n2+...+nN)
用
∑
来简化一下:
(N−2)∑(aini)+∑ai∑ni
可能看上去十分繁琐,但是也不算太难,为了更容易看懂,我写得很详细(一中午的大好光阴,就消逝在这这些数学符号之中……)
优化
但是,储存每个
∑
似乎不大好,我们可以优化一下储存方式:
f[i][0]
表示颜色为
i
,编号为偶数的格子的
f[i][1]
表示颜色为
i
,编号为奇数的格子的
n[i][0]
表示颜色为
i
,编号为偶数的格子数量
枚举编号
i
:
提一个
i
:
完了~
记得随时mod哦~
代码
#include<cstdio>
int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
#define MAXN 100000
#define MAXM 100000
#define MOD 10007
int N,ans;
int f[MAXM+5][2],n[MAXM+5][2];
int Number[MAXN+5],Color[MAXN+5];
int main()
{
N=read();
read();
for(int i=1;i<=N;i++)
Number[i]=read()%MOD;
for(int i=1;i<=N;i++)
{
Color[i]=read();
f[Color[i]][i&1]=(f[Color[i]][i&1]+Number[i])%MOD;
n[Color[i]][i&1]++;
}
for(int i=1;i<=N;i++)
ans=(ans+(((n[Color[i]][i&1]-2)%MOD*Number[i]%MOD+f[Color[i]][i&1])%MOD)*(i%MOD)%MOD)%MOD;
printf("%d",ans);
}