前缀和优化
来源:互联网 发布:智能算法优化 编辑:程序博客网 时间:2024/06/07 15:21
在了解之前,先来阐明几个基础概念:
1.时间复杂度O(n):时间复杂度在算法中是一个重要概念,此处O为微积分概念,不做详解。我们可以简记一重循化时间复杂度即为O(n),二重循环时间复杂度为O(n^2),顺推三重循环即为O(n^3)。
e.g.
for(i=1;i<n;i++) for (j=1;j<m;j++) ……
该程序时间复杂度为O(n*m);
这里再附一篇文章进一步帮助了解http://m.blog.csdn.net/firefly_2002/article/details/8008987
2.区间和:即某一区间内所有有元素的和。
e.g.
无序序列:4 5 3 1 9 每个元素的位置记为1 2 3 4 5,此时[2,4]区间和为5+3+1=9。
♢一维前缀和:
先来看这样一个问题:请求出101-1852区间内3的倍数的数的个数。这里我们可以先考虑计算一下1-1852区间内3的倍数的个数再计算1-101区间内3的倍数的个数,相减得到结果,看起来很靠谱的样子,我们可以计算一下:1852|3-101|3=583(“|”是整除的意思),貌似没错,那请继续看下面的例子:计算区间3-12间3的倍数的个数,我们还用上面的方法计算12|3-3|3=3,很明显这一区间内有四个数都是3的倍数,那么问题出在了哪里? 问题出在端点上,如何解决?我们可以对左区间-1处理。
再举个栗子,我们仍以3的倍数为例计算,如果区间为[6-9],那么这个区间中3的倍数的数的个数为2(6和9),这一结论与我们的公式是重合的,可以发现对左区间-1对结果并无影响。再来看,如果我们将左区间数减去2,好像仍然对结果无影响,但是你大可以仔细想想就能轻松举出反例(如区间[7-9],我们理想中的结果是1,但我们计算却发现结果是2),同理-3更无法成立。
好的给最终公式:r/k-(l-1)/k
k即为所求的基数
下面我们就来具体讲解:
首先我们要引入一个f数组,这个数组有用么,当然。f数组存储了1+2+3+…….+n的大小,即1—n的所有数的和,这就是我们的主题,前缀和。比如f[4]=1+2+3+4=10; 知道了这个概念后我们先考虑一个问题:区间[101,1001]的区间和是多少?这时我们就应该返回到我们的第一个问题,是否可以先求解[1,1001]的区间和,再求出[1-101]的区间和,相减得到结论
#include <iostream>#include <cstdio>using namespace std;int main(){ int sum=0; for(int i=101;i<=1001;i++){ sum+=i; } cout<<sum; return 0;}
这样当然可以但是应用起来不灵活
所以前缀和的思路:
f([0,1])=0+1
f([0,2])=0+1+2
f([0,3])=0+1+2+3
f([0,4])=0+1+2+3+4
对比一下可以发现随着右半区间数的递增,f数组的值不断的加右区间新数,而右区间以左的数较上一区间却未变。公式:f[n]=f[n-1]+a[n] (a[n]指代新数)
然后就很好懂了啊,代码:
#include <iostream>#include <cstring>using namespace std;int f[10001],a[10001]; int main(){ int left,right; //定义区间左右端点 cin>>left>>right; //求某区间的区间和 memset(f,0,sizeof(f)); //数组清空 //先求出1-1001各数的前缀和 (预处理) for(int i=1;i<=right;i++) f[i]=f[i-1]+i; //这里将序列定为单调递增序列,所以用i代a[i],择情况而视 cout<<f[right]-f[left-1]; //输出区间和 return 0;} //预处理复杂度为O(n),查询复杂度为O(1)
接下来我们进一步探讨二维的前缀和,也就是在平面内处理矩阵的问题
二维前缀和:
一维前缀和解决的是线性问题,也就是在一维状态下解决区间和问题,那么二维前缀和就是在平面内解决区间和问题,这里我们要再引入一个概念:矩阵。
这里我们需要了解的矩阵只是一个用数字填充的图的概念,如图即为一个3x3的数字矩阵:
1 2 3
4 5 6
7 8 9
那么二维的的前缀和有什么用呢?
毫无疑问仍然是在解决区间和问题的应用,矩阵区间和?其实很简单,矩阵的区间和就是指某矩阵右下端点
至该矩阵左上端点的矩阵的所有元素的和(这里我们直接用矩阵右下端点来表示一个以右下端点到点(1,1)的矩阵).
e.g.
矩阵
14 6 54
3 3 9
8 12 24
中(2,2)-(3,3)矩阵的矩阵区间和为3+9+12+24;
很简单吧(确实是这样),那么如果我们把这个矩阵扩展为10000*10000大小的矩阵,再去求矩阵区间和,不由得????好吧,我们还是返回解释一维区间和的问题,类比一下,好像有了点思路,我们貌似可以先求出(3,3)的矩阵大小再减去(2,2)的矩阵大小,(jiang信jiang疑),但这是有问题的,画图求知:
如图(3,3)矩阵减去(2,2)矩阵得到的是黑色与橘色部分的和而非我们期待中的橘色部分。
那么如何解决呢,我们应该换个思路
这里我们就能够用到小学数学中的容斥原理:
S(4)=S(1+2+3+4)-S(1+3)-S(1+2)+S(1);
所以我们只要求解矩阵1+3,1+2,1,1+2+3+4的大小相减即可得到矩阵区间和,同样的我们引入二维f数组,代表某端点至(1,1)的矩阵大小:
e.g.有一个5x5的矩阵,请输入该矩阵的各个元素,并输入要求解的矩阵区间,上代码:
#include <iostream>#include <cstdio>using namespace std;int f[101][101],a[10][10];int main(){ for(int i=1;i<=5;i++){ for(int j=1;j<=5;j++){ cin>>a[i][j]; f[i][j]=f[i-1][j]+f[i][j-1]+a[i][j]; } } int x,x1,y,y1; cin>>x>>y>>x2>>y2; cout<<f[x2][y2]-f[x2][y-1]-f[x-1[y2]+f[x-1][y-1]; return 0;}
注意这里x-1,y-1是为了包含该矩阵边界
- 前缀和优化
- HDU 5550 dp + 前缀和优化
- CDOJ 1307 ABCDE dp, 前缀和优化
- LightOJ 1193 Dice (II)(前缀和优化dp)
- 1044: [HAOI2008]木棍分割 二分答案+DP+前缀和优化
- lightoj 1145 - Dice (I) 前缀和优化DP
- lightoj 1193 - Dice (II) 前缀和优化DP
- codeforces 708E——前缀和优化dp
- CF - 712D 差值dp + 前缀和优化
- 最大值 (补档) dp+前缀和优化
- hdu 1081 最大子矩阵(二维前缀和优化)@
- codeforces712D Memory and Scores(前缀和优化dp)
- 洛谷P1083 noip 2012 借教室 二分+前缀和优化
- hihocoder1475 数组分拆【DP+前缀和优化】
- hiho #1475 : 数组分拆(前缀和优化+DP)@
- 【bzoj1096】【ZJOI2007】仓库建设(dp+前缀和+斜率优化)
- 【HDU2829】Lawrence-DP+四边形不等式优化+前缀和
- [AHOI2009] BZOJ2431 逆序对数列-动态规划-前缀和优化
- Hello World!
- Linux目录结构
- 瑞士银行推出比特币期货,押注加密货币
- 新加坡金管局发布“数字代币产品指南”
- mongodb基础操作
- 前缀和优化
- mysql解压版的配置方法
- [Design Pattern]工厂模式
- opencv中的BackgroundSubtractorKNN源码解读
- 10 JSP beanutils EL
- Windows Server2012无法打开运行空间池-服务器管理器WinRM插件可能已损坏或丢失
- 在python3中,关于redis读取数据带有‘b’的问题
- 洛谷P2983 [USACO10FEB]购买巧克力Chocolate Buying
- request和requestScope