Luogu P5686 [CSP-SJX2019]和积和
Description–
给定两个下标从
1
1
1到
n
n
n编号的序列
a
i
,
b
i
ai, bi
ai,bi
定义函数
S
(
l
,
r
)
(
1
<
=
l
<
=
r
<
=
n
)
S(l, r)(1 <= l <= r <= n)
S(l,r)(1<=l<=r<=n)为
请你求出下列式子的值:
由于答案可能很大,你只需要给出答案模
1
0
9
+
7
10^9 + 7
109+7 后的结果。
Input–
第一行一个正整数
n
n
n表示序列长度
第二行
n
n
n个正整数表示
a
i
ai
ai
第三行
n
n
n个正整数表示
b
i
bi
bi
Output–
仅一行一个整数表示答案模 1 0 9 + 7 10^9 + 7 109+7 后的结果。
Sample Input–
样例1
3
2 3 4
3 4 5
样例2
244
Sample Output–
样例1
5
11 22 33 44 55
12 34 56 78 90
样例2
201542
说明–
对于 10% 的数据
n
<
=
10
,
a
i
,
b
i
<
=
10
n <= 10, ai,bi <= 10
n<=10,ai,bi<=10
对于 10% 的数据
n
<
=
200
,
a
i
,
b
i
<
=
200
n <= 200, ai,bi <= 200
n<=200,ai,bi<=200
对于 10% 的数据
n
<
=
3000
,
a
i
,
b
i
<
=
1
0
5
n <= 3000, ai,bi <= 10^5
n<=3000,ai,bi<=105
对于 10% 的数据
3
<
=
n
<
=
5
∗
1
0
5
,
1
<
=
a
i
,
b
i
<
=
5
∗
1
0
5
3 <= n <= 5 * 10^5, 1 <= ai,bi <= 5 * 10^5
3<=n<=5∗105,1<=ai,bi<=5∗105
解题思路–
显然,暴力不太可
设前缀和 a a a为 p a pa pa,前缀和 b b b为 p b pb pb
70pts
先前缀和处理数组
a
a
a和数组
b
b
b
则
S
(
l
,
r
)
S(l, r)
S(l,r)可以优化为
(
p
a
[
r
]
−
p
a
[
l
−
1
]
)
∗
(
p
b
[
r
]
−
p
b
[
r
−
1
]
)
(pa[r] - pa[l - 1]) * (pb[r] - pb[r - 1])
(pa[r]−pa[l−1])∗(pb[r]−pb[r−1])
100pts
对式子进行拆分优化
以 n = 2 n = 2 n=2 为例
S(1, 1) = pa[1] * pb[1]
S(1, 2) = pa[2] * pb[2]
S(2, 2) = pa[2] * pb[2] - pa[1] * pb[2] - pa[2] * pb[1] + pa[1] * pb[1]
则结果为S(1, 1) + S(1, 2) + S(2, 2)
= pa[1] * pb[1] + pa[2] * pb[2] + pa[2] * pb[2] - pa[1] * pb[2] - pa[2] * pb[1] + pa[1] * pb[1]
= 2 * (pa[1] * pb[1] + pa[2] * pb[2]) - (pa[1] * pb[2] + pa[2] * pb[1])
然后减去 (pa[1] * pb[1] + pa[2] * pb[2]) 再加上 (pa[1] * pb[1] + pa[2] * pb[2])
得 3 * (pa[1] * pb[1] + pa[2] * pb[2]) - (pa[1] + pa[2]) * (pb[1] + pb[2])
于是式子的规律为
代码–
70pts
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const ll M = 1e9 + 7;
ll n, ans;
struct ooo
{
int x, sum;
}a[500005], b[500005];
ll s(ll x, ll y)
{
ll aa = a[y].sum - a[x - 1].sum;
ll bb = b[y].sum - b[x - 1].sum;
return aa * bb % M;
}
int main()
{
scanf("%lld", &n);
for (ll i = 1; i <= n; ++i)
scanf("%lld", &a[i].x), a[i].sum = (a[i - 1].sum + a[i].x) % M;//前缀和
for (ll i = 1; i <= n; ++i)
scanf("%lld", &b[i].x), b[i].sum = (b[i - 1].sum + b[i].x) % M;
for (ll l = 1; l <= n; ++l)
for (ll r = l; r <= n; ++r)
ans = (ans + s(l, r)) % M;
printf("%lld", ans);
return 0;
}
100pts
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const ll M = 1e9 + 7;
ll n, ans, suma, sumb;
struct ooo
{
int x, ss;
}a[500005], b[500005];
int main()
{
scanf("%lld", &n);
for (ll i = 1; i <= n; ++i)
{
scanf("%lld", &a[i].x);
a[i].ss = (a[i - 1].ss + a[i].x) % M;
suma = (suma + a[i].ss) % M;
}
for (ll i = 1; i <= n; ++i)
{
scanf("%lld", &b[i].x);
b[i].ss = (b[i - 1].ss + b[i].x) % M;
sumb = (sumb + b[i].ss) % M;
}
for (int i = 1; i <= n; ++i)
ans = (ans + (((n + 1) * a[i].ss) % M * b[i].ss) % M) % M;
ans = (ans - suma * sumb % M + M) % M;
printf("%lld", ans);
return 0;
}