一道找规律与推导的题目。
题目
展开题目
一条狭长的纸带被均匀划分出了个格子,格子编号从到。每个格子上都染了一种颜色用当中的一个整数表示),并且写了一个数字。
定义一种特殊的三元组:,其中都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
是整数,
满足上述条件的三元组的分数规定为。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数和表纸带上格子的个数,表纸带上颜色的种类数。
第二行有用空格隔开的正整数,第数字表纸带上编号为格子上面写的数字。
第三行有用空格隔开的正整数,第数字表纸带上编号为格子染的颜色。
输出格式
一个整数,表示所求的纸带分数除以所得的余数。
6 25 5 3 2 2 22 2 1 1 2 1
82
15 45 10 8 2 2 2 9 9 7 7 5 6 4 2 42 2 3 3 4 3 3 2 4 4 4 4 1 1 1
1388
【输入输出样例 1 说明】
纸带如题目描述中的图所示。
所有满足条件的三元组为: 。
所以纸带的分数为。
对于第 组至第 组数据, ;
对于第 组至第 组数据, ;
对于第 组至第 组数据, ,且不存在出现次数超过 的颜色;
对于全部 组数据 ,
解答
表示的显然是距离相等,也就是 是 的平均数,而且 是个整数,所以 奇偶性相同,分别进行计算即可。
又因为颜色与答案无关,所以颜色也可以分别计算。现在的问题就转化为了求:
展开后会发现当中有 个 ,和所有 相乘。利用多项式乘法的特性,可得原式等于:
代码就很简单了:
查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#define pii pair<int, int>
#define X first
#define Y second
using namespace std;
const int MOD = 10007;
int n, m;
int number[100005], color[100005];
vector <pii> v[100005][2];
int main(void)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d", number + i), number[i] %= MOD;
for (int i = 1; i <= n; ++i) scanf("%d", color + i);
for (int i = 1; i <= n; ++i)
v[color[i]][i & 1].push_back(make_pair(i, number[i]));
int ans = 0;
for (int op = 0; op < 2; ++op)
{
for (int i = 1; i <= m; ++i)
{
int R = v[i][op].size();
if (R >= 2)
{
int res = 0, ret = 0;
for (int j = 0; j < R; ++j)
res = (res + v[i][op][j].X) % MOD, ret = (ret + v[i][op][j].Y) % MOD;
ans = (ans + res * ret % MOD) % MOD;
for (int j = 0; j < R; ++j)
ans = (ans + (R - 2) % MOD * v[i][op][j].X % MOD * v[i][op][j].Y % MOD) % MOD;
}
}
}
printf("%d\n", ans);
return 0;
}