前缀和
鸣谢
二维前缀和
激光炸弹
解题思路:
解法思路:我们首先观察题目,可以建立一个数组f[i][j]表示坐标为(xi,yj)(xi,yj)上的权值,那么我们接着思考,因为题目上面说了要求算出这个边长为r的正方形面积,而且整个题目中,只有查询操作,没有修改操作,且内存只要略微省着用,就可以满足O(n2)O(n2)的条件,所以我们可以确认这一题可以使用二维前缀和。
代码:
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,r;
int g[5010][5010];
int main(){
scanf("%d%d",&n,&r);
r = min(5001,r); // 变了这里
for(int i=1;i<=n;++i){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
x++,y++;
g[x][y] += w;
}
for(int i=1;i<=5001;++i)
for(int j=1;j<=5001;++j)
g[i][j] += g[i-1][j] + g[i][j-1] - g[i-1][j-1];
int res = 0;
for(int i=r;i<=5001;++i)
for(int j=r;j<=5001;++j)
res = max(res,g[i][j] - g[i][j-r] - g[i-r][j] + g[i-r][j-r]);
printf("%d\n",res);
return 0;
}
差分
求差分
求出a 的差分序列 b , b 1 = a 1 , b i = a i − a i − 1 ( 2 < = i < = n ) b_1 = a_1,b_i = a_i - a_{i-1} (2 <= i <= n) b1=a1,bi=ai−ai−1(2<=i<=n)
代码:
// a 从下标一开始存
// 如果用原来的 数组求差分序列,要从后向前 求,因为要保留 a[i-1]
for(int i = n ; i>1;--i)
a[i] = a[i] - a[i-1];
差分求区间修改
把区间a[l ,r] 都加上一个 数 d;
b
[
l
]
+
=
d
,
b
[
r
+
1
]
+
=
d
b[l] += d , b[r+1] += d
b[l]+=d,b[r+1]+=d
把区间a[l ,r] 都减去一个 数 d;
b
[
l
]
−
=
d
,
b
[
r
+
1
]
+
=
d
b[l] -= d , b[r+1] += d
b[l]−=d,b[r+1]+=d
增减序列
解题思路:
首先明确 将所有的数一样大,那么从2~n的差分序列都为0,b[1] 可以不为0.都与b[1] 一样即可。在操作的时候我们采取贪心的思路,因为每一次操作都是一正一负,至于为什么要是正负配对,因为我们是要这个B序列2~n都要为0,所以这样负数增加,正数减少,就可以最快地到达目标为0的状态。
至于那些无法配对的数BkBk可以选B1B1或者Bn+1Bn+1,这两个不影响的数,进行修改。
因此最小操作次数为:
m
i
n
(
p
o
s
,
n
e
g
)
+
a
b
s
(
p
o
s
−
n
e
g
)
=
m
a
x
(
p
o
s
,
n
e
g
)
min(pos,neg) + abs(pos-neg) = max(pos,neg)
min(pos,neg)+abs(pos−neg)=max(pos,neg)
种类数:
a
b
s
(
p
o
s
−
n
e
g
)
+
1
abs(pos -neg)+1
abs(pos−neg)+1
代码:
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
int n;
ll a[N];
ll psum,nsum;
int main(){
scanf("%d",&n);
psum = nsum = 0;
for(int i = 1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i = n ; i>1;--i)
a[i] = a[i] - a[i-1];
for(int i = 2;i<= n ;++i)
if(a[i] > 0)
psum += a[i];
else
nsum -= a[i]; // 加负数的绝对值,那么直接减就好
printf("%lld\n%lld\n",max(psum,nsum),abs(psum - nsum) + 1);
return 0;
}
最高的牛
解题思路:
代码:
#include<stdio.h>
#include<stdlib.h>
#include<map>
using namespace std;
const int N = 1e4 + 10;
// 用map 和 pair 来记录是否重复
map <pair<int ,int>,bool> vis;
int a[N],b[N];
int n,p,h,m;
int x,y;
int main(){
scanf("%d%d%d%d",&n,&p,&h,&m);
for(int i=1;i<= m ;++i){
scanf("%d%d",&x,&y);
if(x>y)swap(x,y);
if(vis[make_pair(x,y)])continue;
b[x+1]-- , b[y]++ ; // 所以不能 x++
vis[make_pair(x,y)] = 1; // 因为这里还要用到 x
}
for(int i=1;i<=n;++i){
a[i] = a[i - 1] + b[i];
printf("%d\n",h+a[i]);
}
return 0;
}