洛谷 P5686 [CSP-SJX2019]和积和

思路

应用多个前缀和推出式子即可

\(30pts\):

首先如果暴力算的话很简单,直接套三层循环就好了(真的是三层!!最后两个\(sigma\)一起算就好了)

\[\sum_{l = 1}^{n}\sum_{r = l}^{n}\sum_{i = l}^{r}a[i]\sum_{i = l}^{r}b[i]
\]

\(70pts\):

其实不用这么麻烦,我们发现最后两个\(sigma\)可以用前缀和\(O(1)\)算出来,这样就可以\(70\)分了(见代码\(sub1\))

\(100pts\):

考虑再拆一层循环(这里用\(SA\)和\(SB\)数组表示70分钟\(a\)数组和\(b\)数组的前缀和)

我觉得你可以自己展开式子(毕竟不能太懒嘛)

然后就会得到这样一个式子

\[\sum_{l = 1}^{n}(SA[l] * SB[l] + SA[l + 1] * SB[l + 1] + ...+SA[n] * SB[n]) - (SA[l] + SA[l + 1] + ... + SA[n]) * SB[l - 1] - (SB[l] + SB[l + 1] + ... + SB[n]) * SA[l - 1] + (n - l + 1) * SA[l - 1] * SB[l - 1]
\]

我们发现这些东西基本都可以用前缀和再求一遍,所以我们要求一下\((SA[l] * SB[l] + SA[l + 1] * SB[l + 1] + ...+SA[n] * SB[n])\)的前缀和(代码中为\(woc\)数组),求一下\(SA\)数组的前缀和(代码中为\(qza\)数组),求一下\(SB\)数组的前缀和(代码中为\(qzb\)数组),然后就可以\(O(n)\)做这道题啦

下面上代码

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std; const int A = 5e5 + 11;
const int mod = 1e9 + 7; inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + c - 48;
return x * f;
} int n, a[A], b[A], ans = 0, SA[A], SB[A], qza[A], qzb[A];
int woc[A]; void sub1() {
for(int l = 1; l <= n; l++) {
for(int r = l; r <= n; r++) {
ans = (ans + ((SA[r] - SA[l - 1]) % mod + mod) % mod * ((SB[r] - SB[l - 1]) % mod + mod)) % mod;
}
}
cout << ans << '\n';
return;
} signed main() {
n = read();
for(int i = 1; i <= n; i++) a[i] = read(), SA[i] = (SA[i - 1] + a[i]) % mod;
for(int i = 1; i <= n; i++) b[i] = read(), SB[i] = (SB[i - 1] + b[i]) % mod;
if(n <= 3000) return sub1(), 0;
for(int i = 1; i <= n; i++) woc[i] = (woc[i - 1] + SA[i] * SB[i]) % mod;
for(int i = 1; i <= n; i++) qza[i] = (qza[i - 1] + SA[i]) % mod;
for(int i = 1; i <= n; i++) qzb[i] = (qzb[i - 1] + SB[i]) % mod;
for(int i = 1; i <= n; i++) {
int fuck1 = ((woc[n] - woc[i - 1]) % mod + mod) % mod;
int fuck2 = ((qza[n] - qza[i - 1]) % mod + mod) % mod * SB[i - 1] % mod;
int fuck3 = ((qzb[n] - qzb[i - 1]) % mod + mod) % mod * SA[i - 1] % mod;
int fuck4 = (((n - i + 1) % mod * SA[i - 1] % mod * SB[i - 1]) % mod + mod) % mod;
int now = fuck1 - fuck2 - fuck3 + fuck4;
ans = ((ans + now % mod) % mod + mod) % mod;
}
cout << ans << '\n';
return 0;
}

最新文章

  1. Redis不同类型方法整合
  2. 【解决】SharePoint 2013 with SP1安装问题及解决
  3. git --- push到远端
  4. Flex与.net进行URL参数传递编码处理
  5. JavaScript DOM高级程序设计2.3 this--我要坚持到底!
  6. 计算器(console version)
  7. BAT-使用BAT方法判断网络启动EXE(快捷方式)
  8. codevs 1993 草地排水 USACO
  9. BZOJ 2882 工艺 (字符串最小循环同构)
  10. 解决HTML5中placeholder属性兼容性的JQuery插件
  11. 我的Java笔记
  12. 【转】linux IO子系统和文件系统读写流程
  13. 使用listview空控件展示数据
  14. linux常用命令 grep命令
  15. Runaway argument错误 [Overleaf: 在线Latex] [Type 3问题后续]
  16. 《统计学习方法》笔记(9):EM算法和隐马尔科夫模型
  17. POJ 2719
  18. python textwrap.md
  19. Orleans入门
  20. squeeze()

热门文章

  1. 最近几周,写了个微信好友检测助手App
  2. SQL Server通过条件搜索获取相关的存储过程等对象
  3. Java_map的key为自定义对象
  4. C语言 复习函数
  5. 搭建Harbor
  6. 数组类的创建——DynamicArray.h
  7. 使用webstrom开发小程序要做的设置
  8. PHPStorm 初遇 Xdebug (xdebug代码调试及性能分析)
  9. 各种数和各种反演(所谓FFT的前置知识?)
  10. 安装Linux操作系统,学习Linux基础