五个小技巧node
a为原数组,从第一项开始数组
前缀和顾名思义,前面的和,具体来讲就是前n项的和
sum为前缀和数组spa
第n项的前缀和等于第n-1项前缀和+第i项数之和
\(\sum_{1}^{n}a[i]=\sum_{1}^{n-1}a[i]+a[i]\)指针
sum[i]=sum[i-1]+a[i];
应用
求静态区间和
例如求 a[i]区间[l,r]的和
\(\sum_{i=l}^{r}a[i]=\sum_{i=1}^{r}a[i]-\sum_{i=1}^{l-1}a[i]\)code
\(\sum_{i=1}^{n}\sum_{j=1}^{n}a[i][j]=\sum_{i=1}^{n-1}\sum_{j=1}^{n}a[i][j]+\sum_{i=1}^{n}\sum_{j=1}^{n-1}a[i][j]+a[n][n]-\sum_{i=1}^{n-1}\sum_{j=1}^{n-1}a[i][j]\)
(至于怎么推出来的,建议自行画个图表示一下)blog
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
应用与一维相似排序
差分 为 相差的数队列
定义cf[n]为差分序列
\(cf[i]=a[i]-a[i-1]\)
应用
区间求加数后的第i个数
例如一个区间[l,r]都加上一个数x,求第i个数
求第n个数,设第i个数为y
\(y=\sum_{i=1}^{n}cf[i]\)ip
当[l,r]加上一个数x,cf[l+1,r]都不会发生改变
只有\(cf[l]=a[l]+x-a[l-1]=cf[l]+x,cf[r+1]=a[r+1]-(a[r]+x)=cf[r+1]-x\)get
\(a[i]=sum[i]-sum[i-1]\)
\(cf[i]=a[i]-a[i-1]\)
这里借鉴一维的变化
推出二维的差分
(为何能推出来,由于前缀和的差分就是原数列,又由于差分的前缀和是原数列,因此由前缀和差分获得的原序列一样适用于由原序列差分获得差分序列)
\(a[i][j]=sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]\)
\(cf[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]\)
应用与一维相似
至于与一位的差别
好比给以\(x_1,y_1\)为左上角,\(x_2,y_2\)为右下角的矩阵都加上x
此时cf数组就要进行以下操做
cf[x1][y1]+=x; cf[x1][y2+1]-=x; cf[x2+1][y1]-=x; cf[x2+1][y2+1]+=x;
依次来看
根据前缀和性质
\(cf[x1][y1]+=x\) 整个黄色部分在求其a[i][j]\(i>x_1 和j>y_1\)时都会因其影响
\(cf[x1][y2+1]-=x\) 同理蓝色部分会消除影响
\(cf[x2+1][y1]-=x\) 同理蓝色部分会消除影响
\(cf[x2+1][y2+1]+=x\) 消除两个蓝色过分消除的影响
离散化是在考虑数与数之间的大小关系而不考虑具体数值的状况下使用
好比序列 \(1,100000,2999\)
有两种离散化方式
这里介绍一种
以值为排序,用下标代替原来的值
容易知道 \(1,2999,100000\)
下标代替原来的值为\(1,2,3\)
struct node{ int val,p; }s[maxn]; bool cmp(node a,node b){ return a.val<b.val; } sort(s+1,s+1+n,cmp);
双指针不是c语言中的指针
而是用两个变量遍历
举例就懂了,好比二分查找时的l,r 还有就是如今手写快速排序时,左右指针找大于小于中间数的值
思路就是两遍跑单调队列,一遍维护单调单调递增序列,一遍维护单调递减序列
重点介绍怎么维护单调队列
单调队列,是在队列的基础上,使队列一样具备单调性(注意区分单调队列和优先队列)这个单调性可根据本身定义来(最小值啊,最大值啊,其余...
*code
#include<cstdio> using namespace std; int n,k; int a[1000000+10]; int q[1000000+10],p[1000000+10]; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int head=1,tail=0; for(int i=1;i<=n;i++) { while(head<=tail && q[tail]>=a[i]) --tail;//找到比他小的数为止 q[++tail]=a[i];//不然入队列 p[tail]=i; while(p[head]<=i-k) head++;//窗口后移一次,第一个元素过期 下标比较 if(i>=k) printf("%d ",q[head]); //i大于窗口长度时循环一次输出一次 输出队列最小值 } printf("\n"); head=1,tail=0;//重置队列,再次从新从头找最大值 for(int i=1;i<=n;i++) { while(head<=tail && q[tail]<=a[i]) tail--;//找到比他大的数为止 q[++tail]=a[i];//不然入队列 p[tail]=i; while(p[head]<=i-k) head++;//窗口后移一次,第一个元素过期 下标比较 if(i>=k) printf("%d ",q[head]); //i大于窗口长度时循环一次输出一次 输出队列最大值 } }