题目
[NOIP2015 普及组] 求和
题目背景
NOIP2015 普及组 T3
题目描述
一条狭长的纸带被均匀划分出了n个格子,格子编号从1到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<=100000)
题解
首先一眼看出结果和y没有半毛钱关系,y唯一限制的地方是x,z的奇偶性必须相同
所以我们可以得出要想统计进入答案的格子之间必须同奇偶且同颜色,我们把有相同奇偶性和颜色的格子分成一组。
我们考虑其中的一组,考虑差值法,看一下每加入一个新的数会对答案产生多少的贡献
画出图表容易知道
number\编号 |
1 |
2 |
3 |
4 |
n_1 |
1 |
|
|
1 |
n_2 |
|
1 |
|
1 |
n_3 |
|
|
1 |
1 |
n_4 |
1 |
1 |
1 |
1+1+1 |
例如加入了该组的第四个,产生的贡献如下
然后前缀和统计,计算即可
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include<bits/stdc++.h> #define int long long using namespace std;
int n, m;
const int N = 100100; const int mod = 10007;
int counta[N][2], sum_n[N][2], sum_f[N][2], sum_fn[N][2]; int a[N], b[N];
int read() { int f = 1, x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return f * x; }
signed main() { n = read(), m = read(); long long ans = 0; for(int i = 1;i <= n;i++) { a[i] = read(); }
for(int i = 1;i <= n;i++) { b[i] = read(); }
for(int i = 1;i <= n;i++) { ans = (ans + sum_fn[b[i]][i % 2]) % mod; counta[b[i]][i % 2] ++; sum_f[b[i]][i % 2] = (sum_f[b[i]][i % 2] + i) % mod; sum_n[b[i]][i % 2] = (sum_n[b[i]][i % 2] + a[i]) % mod; sum_fn[b[i]][i % 2] = (sum_fn[b[i]][i % 2] + (i * a[i]) % mod) % mod; ans = (ans + (i * sum_n[b[i]][i % 2]) % mod) % mod; ans = (ans + (a[i] * sum_f[b[i]][i % 2]) % mod) % mod; ans = (ans + (( (counta[b[i]][i % 2] - 3) * i * a[i]) % mod + mod ) % mod) % mod; } printf("%lld", ((ans % mod) + mod) % mod); return 0; }
|