链接:https://www.luogu.com.cn/problem/P2671
上题干:
题目描述
一条狭长的纸带被均匀划分出了n个格子,格子编号从11到n。每个格子上都染了一种颜色colori用[1,m]当中的一个整数表示),并且写了一个数字numberi。
定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
xyz是整数,x<y<z,y−x=z−y
colorx=colorz
满足上述条件的三元组的分数规定为(x+z)×(numberx+numberz)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数n表式纸带上格子的个数,m表纸带上颜色的种类数。
第二行有n用空格隔开的正整数,第i数字number表纸带上编号为i格子上面写的数字。
第三行有n用空格隔开的正整数,第i数字color表纸带上编号为i格子染的颜色。
输出格式
一个整数,表示所求的纸带分数除以1000710007所得的余数。
输入输出样例
输入 #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,3,5),(4,5,6)。
所以纸带的分数为(1+5)×(5+2)+(4+6)×(2+2)=42+40=82(1+5)×(5+2)+(4+6)×(2+2)=42+40=82。
对于第 11 组至第 22 组数据,1≤n≤100,1≤m≤5;
对于第33 组至第 44 组数据, 1≤n≤3000,1≤m≤100;
对于第 55 组至第66组数据, 1≤n≤100000,1≤m≤100000,且不存在出现次数超过20的颜色;
对 于 全 部 1010 组 数 据 , 1≤n≤100000,1≤m≤100000,1≤colori≤m,1≤numberi≤100000
从这道题里,我们可以学到很多东西。
因为每个格子的编号是从1开始的,所以我们定义两个数组,a【i】表示 第i个格子内的数字,
b【i】表示第i个格子的颜色。
然后,这道题给了我们一个三元组(x,y,z),三个编号为x,y,z的格子。
要求这个三元组满足下面两个条件:
第一个条件是,这个三元组内部是严格升序的,并且,y-x=z-y
严格升序都能理解,那么我们接下来研究一下y-x=z-y这个条件想表达什么。
首先呢,不难看出它是一个等差数列。即x,y,z满足等差性质
那么假设公差为d,则有:x+2d=z,因为2d是一个偶数,所以x必然与z共奇偶。
请把这条性质记住。我们为什么会想到这个呢?因为我们是站在枚举复杂度的角度来看的。
假设我们要找到所有满足条件的x,y,z,那么简单的三重枚举就行了,但是会超时。
所以我们必须要找出优化的枚举操作。并带着目的性去审视题目给的条件。
第二个条件是:在(x,y,z)中,编号x的格子颜色要等于,编号为z的格子的颜色
即b【x】=b【z】
满足这两个条件的三元组就可以计入答案,
每一组合法的三元组对答案的贡献是(x+z)*(a【x】+a【z】)
那么这道题到这就结束了吗?
不,还远远没有。
因为以我们现在推出来的条件,我们需要每次枚举x,z的位置(复杂度为O(n^2)),并且判断x,z的奇偶性,颜色是否相同。
这样做仍然无法通过本题(没错就是这么变态)
所以我们还要优化,但是还有哪里能优化呢?我们已经优化了条件,但是你有没有想过,计算答案这个过程是可以优化的。
每一个合法的三元组对答案的贡献可以展开成:x*a【x】+x*a【z】+z*a【x】+z*a【y】
那么x对答案的贡献是什么呢?x*a【x】+x*a【z】
我们简化一下问题:不考虑颜色是否相同,只考虑奇偶性是否相同
假设一对合法三元组为(1,2,3)那么1对答案的贡献是 1*a【1】+1*a【3】;
然后枚举z,当x=1的时候,z可以是5,7,9,11,13......
所以1对答案的贡献就是:(1*a【1】+1*a【3】)+(1*a【1】1*a【5】)+(1*a【1】+1*a【7】)......
假设z枚举到7为止,也就是说如果有4个条件相同的元素(1,3,5,7)那么
1对答案的贡献: 3* (1*a【1】)+a【3】+a【5】+a【7】
等价于: 2*(1*a【1】)+(a【1】+a【3】+a【5】+a【7】)
3对答案的贡献: 3*(3*a【3】)+ 3a【1】+3a【5】+3a【7】
等价于: 2*(3*a【3】)+ 3(a【1】+a【3】+a【5】+a【7】)
我们可以把这个化成i的时候的一般式子,即i对于答案的贡献是 ( 共奇偶的格子数-2)*a【1】+i*(所有的共奇偶的格子上的数字和)
那么把这个东西一般化呢?即 任何 i 对答案的贡献是 a【i】*(满足同一种条件的格子数-2)+i*(满足同一种条件的格子数上面的数字之和)
让我们回到我们的问题,合法的三元组必须满足颜色相同,奇偶相同的性质
所以我们可以同理推理出来: 任何i对答案的贡献都是 a【i】*(共奇偶,且共颜色 的格子的总个数-2)+i*(共奇偶,共颜色的格子上面的数字之和)
所以我们只需要提前算出,共奇偶且共颜色的每个格子上的数字之和,和共奇偶且共颜色的格子总数。
用一个数组来存《共奇偶且共颜色的每个格子上的数字之和》 那么就有前缀和式子: sum【颜色】【奇偶】+= 满足这个条件的格子上的数字
也就是 sum[b[i][i%2]+= a[i];
另一个数组来存《共奇偶且共颜色的格子总数》 有 桶排序 ans【颜色】【奇偶】++;
也就是ans[b[i]][i%2]++;
然后我们就可以线性地求答案了。
只需要枚举i=1~n,每次计算答案,然后取模就可以了 。
代码如下:
const int N = 1e5 + 10;
const int mod = 10007;
int sum, n, m;
int a[N], b[N];
int sum1[N][3];//同色同奇偶的个数
int num[N][3];//同色奇偶的编号和
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> a[i];//输入编号
for (int i = 1; i <= n; i++)
{
cin >> b[i];
sum1[b[i]][i % 2]++;
num[b[i]][i % 2] = (num[b[i]][i % 2]+a[i]) % mod;
}
for (int i = 1; i <= n; i++)
{
sum = (sum+ i *( (sum1[b[i]][i % 2] - 2) * a[i]%mod + num[b[i]][i % 2]) )%mod;
}
cout << sum;
}