简单题,直接将区间求和转换成前缀和,设 \(A_i = \sum_{i = 1}^n a_i,B_i = \sum_{i = 1}^n b_i\),那么式子为:
\[\sum_{l = 1}^n \sum_{r = l}^n (A_r-A_{l-1})(B_r-B_{l-1})\]
\[=\sum_{l = 1}^n \sum_{r = l}^n A_rB_r-A_rB_{l-1}-A_{l-1}B_r+A_{l-1}B_{l-1}\]
很明显 \(O(n)\) 枚举右端点 \(r\),式子变成:
\[\sum_{l = 1}^r A_rB_r-A_rB_{l-1}-A_{l-1}B_r+A_{l-1}B_{l-1}\]
如何快速算出这个式子?
我们有:
\[\sum_{l = 1}^r A_rB_r-A_rB_{l-1}-A_{l-1}B_r+A_{l-1}B_{l-1}=\sum_{l = 1}^r A_rB_r-\sum_{l = 1}^r A_rB_{l-1}-\sum_{l = 1}^r A_{l-1}B_r+\sum_{l = 1}^r A_{l-1}B_{l-1}\]
于是可以将四个单项式分类讨论。
\(A_rB_r\) 很好处理,直接算,由于 \(l\) 有 \(r\) 个取值,所以是 \(rA_rB_r\)。
\(A_rB_{l-1}\) 很明显 \(A_r\) 没有问题,但 \(B_{l-1}\) 需要预处理 \(B\) 的前缀和,也就是前缀和的前缀和。
\(A_{l-1}B_r\) 同理。
\(A_{l-1}B_{l-1}\) 很显然需要另外维护两前缀和之积的前缀和。
代码:- #include<bits/stdc++.h>
- using namespace std;
- const int mod = 1e9+7;
- const int N = 5e5+5;
- int a[N],b[N];
- long long suma[N],sumb[N],prea[N],preb[N],mul[N];
- signed main()
- {
- ios::sync_with_stdio(0);
- cin.tie(0);
- cout.tie(0);
- int n;
- cin >> n;
- for(int i = 1;i<=n;++i)
- {
- cin >> a[i];
- suma[i] = (suma[i-1]+a[i])%mod;
- prea[i] = (prea[i-1]+suma[i])%mod;
- }
- for(int i = 1;i<=n;++i)
- {
- cin >> b[i];
- sumb[i] = (sumb[i-1]+b[i])%mod;
- preb[i] = (preb[i-1]+sumb[i])%mod;
- mul[i] = (mul[i-1]+1ll*suma[i]*sumb[i]%mod)%mod;
- }
- long long sum = 0;
- for(int i = 1;i<=n;++i)
- {
- long long A = i*suma[i]%mod*sumb[i]%mod,B = suma[i]%mod*preb[i-1]%mod,C = sumb[i]%mod*prea[i-1]%mod,D = mul[i-1];
- sum = (sum+(((A-B+mod)%mod-C+mod)%mod+D)%mod)%mod;
- }
- cout << sum;
- return 0;
- }
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |