激光炸弹(二维前缀和)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//https://www.acwing.com/problem/content/101
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

typedef long long ll;

using namespace std;

const int N = 5000 + 10;

int n, r;
int m1, m2;
int sum[N][N];
int ans = 0;

int main()
{
cin >> n >> r;
m1 = m2 = r;
for (int i = 0; i < n; i++)
{
int x, y, w;

cin >> x >> y >> w;
sum[++x][++y] += w;

m1 = max(m1, x);
m2 = max(m2, y);
}

for (int i = 1; i <= m1; i++)
for (int j = 1; j <= m2; j++)
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + sum[i][j];

for (int i = r; i <= m1; i++)
{
for (int j = r; j <= m2; j++)
{
ans = max(ans, sum[i][j] - sum[i][j - r] - sum[i - r][j] + sum[i - r][j - r]);
}
}

cout << ans << endl;

return 0;
}

简单的二维前缀和,计算出所给数据的二维前缀和。

然后遍历半径为R的正方形的右下角,计算出最终的答案。

增减序列(差分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//https://www.acwing.com/problem/content/102/
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>

typedef long long ll;

using namespace std;

const int N = 1e5 + 10;

int n;
int b[N];

int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = n; i >= 1; i--) b[i] -= b[i - 1];

ll pos = 0, neg = 0;
for (int i = 2; i <= n; i++)
{
if (b[i] > 0) pos += b[i];
else neg -= b[i];
}

cout << min(pos, neg) + abs(pos - neg) << endl;
cout << abs(pos - neg) + 1 << endl;

return 0;
}

对区间进行操作,使用差分数组优化操作到O(1)。

结果要求所有数一样,即b[2]~b[n]=0。

每次操作如下:

  • l = 1,r = n + 1:无意义
  • l = 1,r = 2~n:改变b数组一个数(改变1无意义)
  • l = 2~n,r = n + 1:改变b数组一个数(改变n+1无意义)
  • l = 2n,r = 2n(优先):改变b数组两个数,一个加、一个减。

我们可以统计正数和负数的个数,优先同时改变两个数。

剩余的数使用2或3操作进行改变,最终得到最小操作次数。

至于可能的情况,即改变b1的情况(使用2操作的可能次数)+不改变b1的情况(1种)。

最高的牛(差分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//https://www.acwing.com/problem/content/103/
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>

typedef long long ll;

using namespace std;

const int N = 1e5 + 10;

int n, p, h, m;
int height[N];
bool visited[10000 + 10][10000 + 10];

int main()
{
cin >> n >> p >> h >> m;
for (int i = 1; i <= m; i++)
{
int a, b;

cin >> a >> b;
if (a > b) swap(a, b);

if (!visited[a][b])
{
visited[a][b] = true;
height[a + 1]--, height[b]++;
}
}

height[1] += h;
for (int i = 1; i <= n; i++)
{
height[i] += height[i - 1];
cout << height[i] << endl;
}

return 0;
}

题目给出m对关系,即A和B可以相互看到。

给出最高的牛身高是h,求所有牛最大可能的身高。


给出A和B可以相互看到意味着:A和B之间的牛身高最大是min(A-1, B-1)。

不妨假设,初始所有牛身高为0。可以通过差分数组,每次让A和B之间牛的身高减一。

这样,通过前缀和可以计算出原身高相对关系。

然后在原身高的基础上加上最大的身高p,(p原来对应的是0)即可得到答案。