「CodePlus 2017 11 月赛」Yazid 的新生舞会

给定长度为 n105n\le10^5 的序列 aa ,统计满足以下条件的子区间数量

区间 [l,r][l, r] 中,存在一个数 xx ,它的出现次数为 mm,并且 2m>rl+12m>r-l+1


记录一下思考过程

首先觉得是枚举 xx,那么记 si=k=1i[ai=x]s_i = \sum_{k=1}^i [a_i=x]

条件转化为 2(srsl)>rl2(s_r - s_l) > r - l (现在考虑 [l+1,r][l+1, r]

化简一下 2sll<2srr2s_l-l<2s_r-r

那么又记 ci=2siic_i = 2s_i - i

也就是说,若 cl<crc_l<c_r[l+1,r][l+1, r] 满足条件

对于每个 crc_r 都要数出来多少 clc_l 满足,朴素可能是 O(nV)O(nV)

观察 cic_i 的性质,发现其为 1+i=1n[ai=x]1+\sum_{i=1}^n [a_i=x]d=1d=-1 的等差数列组合

还有另外一个思考方式

建立新数组

bi={1   ai=x1   aix b_i = \left\{ \begin{aligned} &1~~~a_i=x\\ -&1~~~a_i\neq x \end{aligned} \right.

建立 bb 的前缀和 ddddcc 完全相同

然后就变成一道数据结构问题

维护序列 aa,支持

  1. 给出 x,yx,y ,区间加 11
  2. 给出 x,yx,y ,回答 i=xyj=1x1ai\sum_{i=x}^y\sum_{j=1}^{x-1}a_i

对应到这个问题,就是定义 px=[ci=x]p_x=\sum[c_i=x](当然这个 pp 是在更新的)

当正在处理 ae=xa_e=x 时(此处的 aa 是原题的)

  1. 处理对 ansans 的贡献
  2. 更新 pp

假设 ffee 之后第一个满足 af=xa_f=x

那么对于 ce,ce+1,,cf1c_e,c_{e+1},\cdots,c_{f-1} 为一个 d=1d=-1的等差数列

g=ce,h=cf1g=c_e,h=c_{f-1} 注意 h<gh<g

i=hgj=i1pj=(gh+1)i=h1pi+i=hg1(gi)pi=(gh+1)i=h1pi+gi=hg1pii=hg1ipi \begin{aligned} \sum_{i=h}^g\sum_{j=-\infin}^{i-1}p_j &=(g-h+1)\sum_{i=-\infin}^{h-1}p_i+\sum_{i=h}^{g-1}(g-i)p_i\\ &=(g-h+1)\sum_{i=-\infin}^{h-1}p_i+g\sum_{i=h}^{g-1}p_i-\sum_{i=h}^{g-1}i\cdot p_i \end{aligned}

即需要维护 pip_iipii\cdot p_i ,可以通过开两个线段树解决,需支持区间求和、修改

常数极其巨大,最长一个点跑了 2.33s(未 -O2)

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, l, r) for (int i = (l); i >= (r); --i)
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::make_pair;
using std::pair;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;

const int N = 500000;
const int FIX = N + 1;

struct S {
struct Seg1 {
struct Node {
Node *ls, *rs;
ll sum, tag;
int clear;
int l, r;
int dis() { return r - l + 1; }
void pushdown() {
if (clear) ls->clear = rs->clear = 1, ls->tag = rs->tag = ls->sum = rs->sum = 0, clear = 0;
ls->sum += ls->dis() * tag, ls->tag += tag;
rs->sum += rs->dis() * tag, rs->tag += tag;
tag = 0;
}
void maintain() { sum = ls->sum + rs->sum; }
} T[8 * N];
int cnt = 0, L, R;
Node* root;
Seg1() { build(root, 1, N + FIX); }
void build(Node*& c, int l, int r) {
c = &T[cnt++];
c->l = l, c->r = r;
if (l == r) return;
int mid = (l + r) / 2;
build(c->ls, l, mid), build(c->rs, mid + 1, r);
}
void clear() { root->sum = root->tag = 0, root->clear = 1; }
void _e(Node* c) {
if (L <= c->l && c->r <= R) {
c->tag += 1, c->sum += c->dis();
return;
}
if (c->r < L || R < c->l) return;
c->pushdown();
_e(c->ls), _e(c->rs);
c->maintain();
}
ll _q(Node* c) {
if (L <= c->l && c->r <= R) return c->sum;
if (c->r < L || R < c->l) return 0;
c->pushdown();
return _q(c->ls) + _q(c->rs);
}
void edit(int l, int r) {
L = l + FIX, R = r + FIX;
_e(root);
}
ll query(int l, int r) {
L = l + FIX, R = r + FIX;
return _q(root);
}
void print(Node* c) {
if (!c) return;
cout << c->l << ' ' << c->r << endl;
print(c->ls), print(c->rs);
}
} s1;
struct Seg2 {
int cnt = 0, L, R;
struct Node {
Node *ls, *rs;
ll sum, tag;
int clear;
int l, r;
ll calc() { return ((ll)l + r - 2 * FIX) * (r - l + 1) / 2; }
int dis() { return r - l + 1; }
void pushdown() {
if (clear) ls->clear = rs->clear = 1, ls->tag = rs->tag = ls->sum = rs->sum = 0, clear = 0;
ls->sum += ls->calc() * tag, ls->tag += tag;
rs->sum += rs->calc() * tag, rs->tag += tag;
tag = 0;
}
void maintain() { sum = ls->sum + rs->sum; }
} T[8 * N];

Node* root;
Seg2() { build(root, 1, N + FIX); }
void build(Node*& c, int l, int r) {
c = &T[cnt++];
c->l = l, c->r = r;
if (l == r) return;
int mid = (l + r) / 2;
build(c->ls, l, mid), build(c->rs, mid + 1, r);
}
void clear() { root->sum = root->tag = 0, root->clear = 1; }
void _e(Node* c) {
if (L <= c->l && c->r <= R) {
c->tag += 1, c->sum += c->calc();
return;
}
if (c->r < L || R < c->l) return;
c->pushdown();
_e(c->ls), _e(c->rs);
c->maintain();
}
ll _q(Node* c) {
if (L <= c->l && c->r <= R) return c->sum;
if (c->r < L || R < c->l) return 0;
c->pushdown();
return _q(c->ls) + _q(c->rs);
}
void edit(int l, int r) {
L = l + FIX, R = r + FIX;
_e(root);
}
ll query(int l, int r) {
L = l + FIX, R = r + FIX;
return _q(root);
}
} s2;
void clear() { s1.clear(), s2.clear(); }
void edit(int l, int r) {
if (l > r) std::swap(l, r);
// cerr << "editing" << endl;
// rep(i, l, r) cerr << s1.query(i, i) << ' ';
// cerr << endl;
s1.edit(l, r), s2.edit(l, r);
// rep(i, l, r) cerr << s1.query(i, i) << ' ';
// cerr << endl;
}
ll query(ll x, ll y) {
if (x > y) std::swap(x, y);
return (y - x + 1) * s1.query(-N, x - 1) + y * s1.query(x, y - 1) - s2.query(x, y - 1);
}
} s;
int n, a[N + 10];
struct X {
struct Node {
int pos;
Node* nxt;
} pool[N + 10];
Node* p[N + 10];
Node* end[N + 10];
int cnt = 0;
void add(int x, int pos) {
pool[cnt].pos = pos, pool[cnt].nxt = nullptr;
// p[x] = &pool[cnt++];
if (p[x] == nullptr)
p[x] = &pool[cnt], end[x] = &pool[cnt];
else
end[x]->nxt = &pool[cnt], end[x] = &pool[cnt];
cnt++;
}
bool empty(int x) { return p[x] == nullptr; }
void del(int x) { p[x] = p[x]->nxt; }
int ask(int x) { return p[x] != nullptr ? p[x]->pos : (n + 1); }
} q;
int main() {
#ifdef LOCAL
freopen("input", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
cout.tie(0);
int t;
cin >> n >> t;
rep(i, 1, n) {
cin >> a[i];
q.add(a[i], i);
}
ll ans = 0;
rep(x, 0, n) {
// cerr << "doing " << x << endl;
if (q.empty(x)) continue;
s.clear();
int pre = 0, lst = 0, cur, nxt;
while (!q.empty(x)) {
cur = q.ask(x);
// cerr << "cur " << cur << endl;
q.del(x);
s.edit(2 * pre - lst, 2 * pre - (cur - 1));
// cerr << "value " << 2 * pre - lst << ' ' << 2 * pre - (cur - 1) << endl;
// cerr << "edit " << lst << ' ' << cur - 1 << endl;
pre++, lst = cur;
nxt = q.ask(x);
// cerr << "ans " << s.query(2 * pre - cur, 2 * pre - (nxt - 1)) << endl;
// cerr << "dbg " << s.s1.query(0, 2 * pre - (nxt - 1)) << endl;
ans += s.query(2 * pre - cur, 2 * pre - (nxt - 1));
}
}
cout << ans;
return 0;
}

「CodePlus 2017 11 月赛」Yazid 的新生舞会

https://gesrua.xyz/archives/题解/Yazid的新生舞会

作者

Gesrua

发布于

2019-10-01

更新于

2020-11-21

许可协议