前缀和 and 差分
前缀和
一维前缀和:
预处理:
求区间[L,R]的和:
二维前缀和:.
预处理:
S[i, j] = 第i行j列格子左上部分所有元素的和
求以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和:
模板题
P2280 [HNOI2003]激光炸弹
洛谷
acwing
题意:
地图上有 N 个目标,,每个目标都有一个价值 Wi。每个炸弹有个范围,求一颗炸弹最多能炸掉地图上总价值为多少的目标。
思路:
二分前缀和
代码:
const int N = 5010; int s[N][N]; int n,r; void solve() { cin>>n>>r; r = min(r, 5001); for(int i=0;i<n;i++){ int x,y,w; cin>>x>>y>>w; s[x+1][y+1]+=w; } //预处理前缀和 for(int i=1;i<=5001;i++) for(int j=1;j<=5001;j++) s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1]; int ans=0; for(int i=r;i<=5001;i++) for(int j=r;j<=5001;j++) ans=max(ans,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]); cout<<ans<<endl; }
差分
思路:
- 想要让上面整体加上,在一个长的数组上是无法实现单方面让上加
- 只有先让 右边的所有数先加上, 在让 右边的减去 , 这样就可以让上加上了
代码:
int insert(int l, int r, int c) { b[l] += c; b[r + 1] -= c; }
应用
增减序列
洛谷
acwing
原文
题意:
给定一个长度为 n 的数列 ,每次可以选择一个区间 ,使下标在这个区间内的数都加一或者都减一。
求
- 至少需要多少次操作才能使数列中的所有数都一样,
- 并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
分析:
先求出差分数组
很明显题意1在差分数组的体现就是: 都为零,B1取值无所谓。
贪心:
- 我们可以,每一次选取,,而且这两个数,一个为正数,一个为负数 。
为什么要是正负配对?因为我们是要这个B序列2~n都要为0,所以这样负数增加,正数减少,就可以最快地到达目标为0的状态。
- 至于那些无法配对的数可以选或者,这两个不影响的数,进行修改。
所以说最少操作数就是 。
p为b序列中正数之和,而q为b序列中负数之和
我们知道经过操作后,数组的值就是b[1]的值。因此数组的情况就是b[1]可能的取值。然后我们贪心过程中,就只有第二步会改变b[1]的值,所以
最终序列a可能会有种情况。
代码:
const int N = 100010; typedef long long LL; int n; int a[N], b[N]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); for (int i = 1; i <= n; i ++ ) b[i] = a[i] - a[i - 1]; LL p = 0, q = 0; for (int i = 2; i <= n; i ++ ) if (b[i] > 0) p += b[i]; else q -= b[i]; cout << max(p, q) << endl; cout << abs(p - q) + 1 << endl; return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/15259183.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步