Address
洛谷P3770
BZOJ4900
UOJ#297
LOJ#2261
Solution
以第一个问题为例,可以设:
a
[
i
]
=
{
1
i
∈
P
−
1
i
∉
P
a[i]=\begin{cases}1&i\in P\\-1&i\notin P\end{cases}
a[i]={1−1i∈Pi∈/P
然后设
a
a
a 的前缀和:
s
u
m
[
i
]
=
s
u
m
[
i
−
1
]
+
a
[
i
]
sum[i]=sum[i-1]+a[i]
sum[i]=sum[i−1]+a[i]
设起点为
x
x
x (
a
[
x
]
=
−
1
a[x]=-1
a[x]=−1 ),那么特征值显然为:
∑
i
=
x
+
1
2
k
+
1
[
s
u
m
[
i
]
−
s
u
m
[
x
]
>
0
]
+
∑
i
=
1
x
−
1
[
−
1
−
s
u
m
[
x
]
+
s
u
m
[
i
]
>
0
]
\sum_{i=x+1}^{2k+1}[sum[i]-sum[x]>0]+\sum_{i=1}^{x-1}[-1-sum[x]+sum[i]>0]
i=x+1∑2k+1[sum[i]−sum[x]>0]+i=1∑x−1[−1−sum[x]+sum[i]>0]
方括号里的东西可以表示成:
s
u
m
[
i
]
>
s
u
m
[
x
]
sum[i]>sum[x]
sum[i]>sum[x]
s
u
m
[
i
]
>
s
u
m
[
x
]
+
1
sum[i]>sum[x]+1
sum[i]>sum[x]+1
于是我们用树状数组可以做到
O
(
k
log
k
)
O(k\log k)
O(klogk) 的复杂度。
但
k
k
k 是
1
0
7
10^7
107 级别,我们需要想办法优化。
发现
s
u
m
[
i
]
sum[i]
sum[i] 等于
s
u
m
[
i
−
1
]
+
1
sum[i-1]+1
sum[i−1]+1 或
s
u
m
[
i
−
1
]
−
1
sum[i-1]-1
sum[i−1]−1 。
所以只需要维护一个指针
p
p
p ,每次查询时根据
a
[
i
]
a[i]
a[i] 的值将指针左移或右移,同时维护
i
i
i 的右边有多少个
s
u
m
>
p
sum>p
sum>p 及左边有多少个数大于
p
+
1
p+1
p+1 。但同时
i
i
i 的值会变,所以
s
u
m
sum
sum 的查询范围也会变(相当于插入 / 删除 一个数),根据与
p
p
p 和
p
+
1
p+1
p+1 的大小关系处理。
第三问一样处理,这时
a
[
i
]
=
{
−
1
i
∈
P
1
i
∉
P
a[i]=\begin{cases}-1&i\in P\\1&i\notin P\end{cases}
a[i]={−11i∈Pi∈/P ,找答案时找
a
[
x
]
=
1
a[x]=1
a[x]=1 的位置
x
x
x ,在
x
x
x 位置的特征值为:
∑
i
=
x
+
1
2
k
+
1
[
s
u
m
[
i
]
−
s
u
m
[
x
]
>
0
]
+
∑
i
=
1
x
−
1
[
1
−
s
u
m
[
x
]
+
s
u
m
[
i
]
>
0
]
\sum_{i=x+1}^{2k+1}[sum[i]-sum[x]>0]+\sum_{i=1}^{x-1}[1-sum[x]+sum[i]>0]
i=x+1∑2k+1[sum[i]−sum[x]>0]+i=1∑x−1[1−sum[x]+sum[i]>0]
复杂度
O
(
k
)
O(k)
O(k) 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
const int E = 2e7 + 1, N = 2e7 + 7, M = N << 1;
int p[N], seed, n, k, S, sum[N], ans1, ans2, ans3, cnt[M], tnc[M], nsum, musn;
int getrand()
{
return seed = ((seed * 12321) ^ 9999) % 32768;
}
void generateData()
{
std::cin >> k >> seed >> S;
int t = 0, i;
n = (k << 1) + 1;
For (i, 1, n) t += (p[i] = getrand() / 128 & 1);
i = 1;
while (t > k)
{
while (!p[i]) i++;
p[i] = 0; t--;
}
while (t < k)
{
while (p[i] == 1) i++;
p[i] = 1; t++;
}
}
int main()
{
int i;
generateData();
For (i, 1, (k << 1) + 1) sum[i] = sum[i - 1] + (p[i] ? 1 : -1);
For (i, 1, (k << 1) + 1) if (p[i])
nsum += sum[i] > 0, cnt[sum[i] + E]++;
For (i, 1, (k << 1) + 1)
{
if (p[i])
{
cnt[sum[i] + E]--;
if (sum[i] > sum[i - 1]) nsum--;
}
if (!p[i]) nsum += cnt[sum[i - 1] + E];
else nsum -= cnt[sum[i] + E];
if (i > 1 && p[i - 1]) tnc[sum[i - 1] + E]++;
if (!p[i]) musn += tnc[sum[i - 1] + 1 + E];
else musn -= tnc[sum[i] + 1 + E];
if (!p[i] && nsum + musn == 0) ans1 = i;
if (!p[i] && nsum + musn == S) ans2 = i;
}
For (i, 1, (k << 1) + 1) sum[i] = sum[i - 1] + (p[i] ? -1 : 1);
nsum = musn = 0;
memset(cnt, 0, sizeof(cnt));
memset(tnc, 0, sizeof(tnc));
For (i, 1, (k << 1) + 1) if (!p[i])
nsum += sum[i] > 0, cnt[sum[i] + E]++;
For (i, 1, (k << 1) + 1)
{
if (!p[i])
{
cnt[sum[i] + E]--;
if (sum[i] > sum[i - 1]) nsum--;
}
if (p[i]) nsum += cnt[sum[i - 1] + E];
else nsum -= cnt[sum[i] + E];
if (i > 1 && !p[i - 1]) tnc[sum[i - 1] + E]++, musn++;
if (p[i]) musn += tnc[sum[i - 1] - 1 + E];
else musn -= tnc[sum[i] - 1 + E];
if (!p[i] && nsum + musn == S) ans3 = i;
}
std::cout << ans1 << std::endl << ans2 << std::endl << ans3 << std::endl;
return 0;
}