题目链接:
https://ac.nowcoder.com/acm/contest/7872/G
题目大意:
给定一个长度为n的序列,需要找出一段最优的连续子段,使得出现在子段中出现次数为1次的数字最多(多一次少一次都不行,只要一次)。
求最优连续子段中出现次数为1次的数字个数。
样例:
输入
4
1 2 1 2
输出
2
思路:
对于一个序列求其最优连续子序列问题,我们可以将其变成:
对于一个固定了右端点的连续子序列,求其最优左端点的问题
那么从左到右,我们每让右端点右移一个元素,就求一遍最优左端点,
对于每次右移,我们可以把左端点分为三类:
(设每次左端点为s,当前右端点为e,第i个位置的元素值为x[i])
第一类,由s到e - 1之内没有出现过x[e]。
第二类,由s到e - 1之内出现过一次x[e]。
第三类,由s到e - 1之内出现过二次及以上的x[e]。
步骤一:对于第一类及第一类以前(第二类和第三类)的s,
我们先假设x[e]都对于其贡献了一次答案,故全部+1
步骤二:对于第二类的s由于x[e]已经不是第一次出现了
那么x[e]和之前x[s]贡献的答案全部要剪掉故全部-2
步骤三:对于第三类的s由于x[e]已经出现过两次,那么其x[s]的贡献在
之前(当这些s曾经为第二类时)就已经被剪掉过 故+1(步骤二多减了)
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int n, px1[maxn], px2[maxn], px3[maxn], xx[maxn];
int tree[maxn << 2];
int treeLaze[maxn << 2];
void update(int ii, int cntL, int cntR, int tL, int tR, int xx);
int readTree(int ii, int cntL, int cntR, int tL, int tR);
void mod1(int ii);
void mod2(int ii);
void mod3(int ii);
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", xx + i);
int res = 0;
for (int i = 1; i <= n; i++) {
mod1(i);
mod2(i);
mod3(i);
px3[xx[i]] = px2[xx[i]];
px2[xx[i]] = px1[xx[i]];
px1[xx[i]] = i;
int tres = readTree(1, 1, n, 1, i);
res = max(tres, res);
}
printf("%d\n", res);
return 0;
}
void pushDw(int ii, int cntL, int cntR)
{
tree[ii] += treeLaze[ii];
if (cntL != cntR) {
treeLaze[ii << 1] += treeLaze[ii];
treeLaze[ii << 1 | 1] += treeLaze[ii];
}
treeLaze[ii] = 0;
}
void pushUp(int ii, int cntL, int cntR)
{
int cntM = (cntL + cntR) >> 1;
if (treeLaze[ii << 1]) pushDw(ii << 1, cntL, cntM);
if (treeLaze[ii << 1 | 1]) pushDw(ii << 1 | 1, cntM + 1, cntR);
tree[ii] = max(tree[ii << 1], tree[ii << 1 | 1]);
}
void update(int ii, int cntL, int cntR, int tL, int tR, int xx)
{
pushDw(ii, cntL, cntR);
if (cntL == tL && cntR == tR) {
treeLaze[ii] += xx;
return;
}
int cntM = (cntL + cntR) >> 1;
if (tR <= cntM) update(ii << 1, cntL, cntM, tL, tR, xx);
else if (tL > cntM) update(ii << 1 | 1, cntM + 1, cntR, tL, tR, xx);
else {
update(ii << 1, cntL, cntM, tL, cntM, xx);
update(ii << 1 | 1, cntM + 1, cntR, cntM + 1, tR, xx);
}
pushUp(ii, cntL, cntR);
}
int readTree(int ii, int cntL, int cntR, int tL, int tR)
{
pushDw(ii, cntL, cntR);
if (cntL == tL && cntR == tR) {
return tree[ii];
}
int cntM = (cntL + cntR) >> 1;
if (tR <= cntM) return readTree(ii << 1, cntL, cntM, tL, tR);
else if (tL > cntM) return readTree(ii << 1 | 1, cntM + 1, cntR, tL, tR);
else {
int tresL = readTree(ii << 1, cntL, cntM, tL, cntM);
int tresR = readTree(ii << 1 | 1, cntM + 1, cntR, cntM + 1, tR);
return max(tresL, tresR);
}
}
void mod1(int ii)
{
static int L;
static int R;
L = 1;
R = ii;
if (L > R) return;
update(1, 1, n, L, R, 1);
}
void mod2(int ii)
{
static int L;
static int R;
L = 1;
R = px1[xx[ii]];
if (L > R) return;
update(1, 1, n, L, R, -2);
}
void mod3(int ii)
{
static int L;
static int R;
L = 1;
R = px2[xx[ii]];
if (L > R) return;
update(1, 1, n, L, R, 1);
}