题目描述
一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。每个格子上都染了一种颜色colori(用[1,m]当中的一个整数表示),并且写了一个数字numberi。
定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
1、x,y,z都是整数,x<y<z,y-x=z-y;
2、colorx=colorz;
满足上述条件的三元组的分数规定为(x+z)×(numberx+numberz)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10007所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数n和m,n代表纸带上格子的个数,m代表纸带上颜色的种类数。
第二行有n个用空格隔开的正整数,第i个数字numberi代表纸带上编号为i的格子上面写的数字。
输出格式
共一行,一个整数,表示所求的纸带分数除以10007所得的余数。
输入样例
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输出样例
82
数据规模
对于全部10组数据,1≤n≤100000,1≤m≤100000,1≤colori≤m,1≤numberi≤100000。
题解
其实这种题关键是要拿出笔来推一下,拆一拆并一并,整理完之后其实就很简单了。
(提前声明,这里为了方便,用$a$表示$number$,用$b$表示$color$)
观察题目,我们可以把条件一转换成$x$和$z$的奇偶性相同。
又有条件二要求$b[x] = b[z]$。
此时我们先设一个$x$,现在我们要求满足上面条件的有关$x$的三元组的和,又设这些三元组的数量为$cnt$,得到:
$$egin{align*} sum_{i = 1}^{cnt}(x, y_{i}, z_{i}) &= sum_{i = 1}^{cnt}(x + z_{i}) imes (a[x] + a[z_{i}]) \ &= sum_{i = 1}^{cnt} x imes a[x] + x imes a[z_{i}] + z_{i} imes a[x] + z_{i} imes a[z_{i}] end{align*}$$
我们又设$sum = a[x] + sum_{i = 1}^{cnt} a[z_{i}]$,可以看出,对于$x$有关的部分也就是:
$$ sum_{i = 1}^{cnt}x imes a[x] + x imes a[z_{i}] = x imes sum + x imes a[x] imes (cnt - 1) $$
对于每一个$x$,我们都可以预处理出对应的$cnt$和$sum$,直接求解就行了。具体细节可以看下面的代码。
#include <cstdio> #define MAX_N 1000000 #define MAX_M 1000000 #define MOD 10007 using namespace std; int n, m; int a[MAX_N | 1]; int b[MAX_N | 1]; int c[MAX_M << 1 | 1]; int s[MAX_M << 1 | 1]; int ans; int main() { scanf("%d%d", &n, &m); for(register int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } for(register int i = 1; i <= n; ++i) { scanf("%d", &b[i]); ++c[b[i] + m * (i & 1)]; s[b[i] + m * (i & 1)] += a[i]; s[b[i] + m * (i & 1)] %= MOD; } for(register int i = 1; i <= n; ++i) { ans += (long long)i * a[i] * (c[b[i] + m * (i & 1)] - 2) % MOD; ans += (long long)i * s[b[i] + m * (i & 1)] % MOD; ans %= MOD; } printf("%d", ans); return 0; }