首先暴力的看待问题,利用前缀和 sa 和 sb 有朴素的n方做法,70pts get!
参考代码片段:
for(int l = 1; l <= n; ++l) {
for(int r = l; r <= n; ++r) {
ans = ans + (sa[r]-sa[l-1]) * (sb[r]-sb[l-1]);
}
}
然后我们把最内层的式子中两括号相乘拆开得到:
\[sa(r)sb(r)-sa(l-1)sb(r)-sa(r)sb(l-1)+sa(l-1)sb(l-1) \]发现两个+项 只和 \(l\) 或 只和 \(r\) 有关,直接一层循环解决。
对于负项,如果我们将 \(l\) 固定,会发现与 \(r\) 有关的部分是一段前缀和的和。
于是就可以求前缀和的前缀和,快乐地A掉这道题辣qwq!
另外注意取模细节,前缀和相减可能减出负数。
参考完整代码:
/*code by Szzkp*/
#include <bits/stdc++.h>
#define Rei register int
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll x = 0;
char f = 0, c = getchar();
while(!isdigit(c)) f |= (c=='-'), c = getchar();
if(f) while(isdigit(c)) x = x*10-c+48, c = getchar();
else while(isdigit(c)) x = x*10+c-48, c = getchar();
return x;
}
const int N = 5e5+5;
const ll mod = 1e9+7;
ll n;
ll sa[N], sb[N];
ll ssa[N], ssb[N];
ll ans;
int main() {
n = read();
for(Rei i = 1; i <= n; ++i) {
sa[i] = (read() + sa[i-1])%mod;
}
for(Rei i = 1; i <= n; ++i) {
sb[i] = (read() + sb[i-1])%mod;
ans = (ans + i*sa[i]%mod*sb[i]%mod + (n-i+1)*sa[i-1]%mod*sb[i-1]%mod)%mod;
}
for(Rei i = 1; i <= n; ++i) {
ssa[i] = (ssa[i-1]+sa[i])%mod;
ssb[i] = (ssb[i-1]+sb[i])%mod;
}
for(Rei i = 1; i <= n; ++i) {
ans = (ans - sa[i-1]*(ssb[n]-ssb[i-1])%mod - sb[i-1]*(ssa[n]-ssa[i-1])%mod + mod) % mod;
}
cout << (ans<0? ans+mod:ans) << "\n";
return 0;
}
撒花!✿✿ヽ(°▽°)ノ✿