ζ

P7809-01 序列

    题解

  1. 第一问
  2. 第二问

在练习ST的时候做了这题,但这其实算是一道思维题。

第一问

想了几个小时,假了几发思路没能想到点上,于是看题解。这道题其实就是要在求给定的区间内找出一个点i,使得点i左边的0的个数和点i右边的1的个数这两个数加起来最大。

到这里,已经知道要求区间的什么最值了,但这两个数的和要怎么求出来?自然想到要用前缀和。假设sum0[i]为从1到i的前缀上的0的个数,sum1[i]为从1到i的前缀上1的个数,那么上面所说的那两个数的和就是

sum0[i]sum0[l1]+sum1[r]sum1[i]=(sum1[r]sum0[l1])+(sum0[i]sum1[i])sum0[i] - sum0[l-1] + sum1[r] - sum1[i] \\ = (sum1[r] - sum0[l-1]) + (sum0[i] - sum1[i])

对于固定的区间[l, r]sum1[r]sum0[l1]sum1[r] - sum0[l-1]的值是固定的。所以只要找出区间内最大的sum0[i]sum1[i]sum0[i] - sum1[i]。ST也就是用来存这个的。

需要注意的是,如果区间上所有的数都是1,区间的i其实应该选在l-1的位置,所以对于每个区间,应该找

maxi=l1r(sum0[i]sum1[i]){max}_{i=l-1}^{r}(sum0[i]-sum1[i])

第二问

简单得很,代码里讲。

需要注意的是,(至少我的代码)这题不用快读不能满分。用了快读之后也需要注意局部性(将稀疏表的j放在前面)。为了便于查看,下面的代码是没有快读的,但考虑了局部性。

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
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>
using namespace std;
short a[5000005];
int st[27][5000005], sum0[5000005], sum1[5000005], pos0[5000005], pos1[5000005], n;
void ST_prework()
{
int i, j, t = log2(n);
for (i = 0; i <= n; i++)
st[0][i] = sum0[i] - sum1[i];
for (j = 1; j <= t; j++)
for (i = 0; i + (1 << j) - 1 <= n; i++)
st[j][i] = max(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);
}
int query(int l, int r)
{
int k = log2(r - l + 1);
return max(st[k][l], st[k][r - (1 << k) + 1]);
}
int main()
{
int i, q, l, r, o, max0, max1, r0, r1;
scanf("%d%d", &n, &q);
for (i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (i = 1; i <= n; i++)
{
sum0[i] = sum0[i - 1];
if (a[i] == 0)
{
sum0[i]++;
pos0[sum0[i]] = i; //记录sum0[i]这个数第一次在sum0这个数组中出现的位置
}
}
for (i = 1; i <= n; i++)
{
sum1[i] = sum1[i - 1];
if (a[i] == 1)
{
sum1[i]++;
pos1[sum1[i]] = i; //同上
}
}
ST_prework();
while (q--)
{
scanf("%d%d%d", &o, &l, &r);
if (o == 2)
{
//如果子段中存在一个"01",最长上升子序列长度为2,否则为1
//若存在"01",则子段中至少有出现一次'1',且在'1'最后一次出现前至少出现过一次'0'
if (pos1[sum1[r]] > l && sum0[pos1[sum1[r]]] > sum0[l - 1])
printf("2\n");
else
printf("1\n");
continue;
}
printf("%d\n", sum1[r] - sum0[l - 1] + query(l - 1, r));
}
return 0;
}
页阅读量:  ・  站访问量:  ・  站访客数: