序
赛季将至,学校搭了 OJ,那么线下比赛开始了。
9/2 DAY 1
难度 NOIP–,但是很抽象,比如说有什么第一题看不懂,第三题暴力能过,第四题
O
(
3
n
)
\mathcal{O(3^n)}
O(3n) 剪枝搜索能过,但是
O
(
n
2
log
n
)
\mathcal{O(n^2 \log n)}
O(n2logn) 的线段树只有二十分。
总之是我太蒻了。
赛时代码
T1 人类基因
TAG:模拟,位运算
赛时没看懂,导致只拿了九分(补交的不算啊)。
题目其实说的是:给
2
n
2n
2n 个数,其中存在的任意两个相同值可以组成一组,总共可以组成
n
−
1
n-1
n−1 组,但有两个数不能组成一组,输出那两个数。
空间只有 10MB,其实排个序就很好把相同的给去掉了,但是也有异或和做法,按二进制位统计,我写的是前者。
code
T2 Bribing Friends
TAG:背包,贪心
USACO 原题,直接放了洛谷链接。是一种动规思想的考察。
赛时想到既然
x
i
x_i
xi 越小越划算,所以就按
x
i
x_i
xi 升序排序,然后从前往后推,要选就尽可能用
x
i
x_i
xi 降到最低价(除最后一个可以降的都降到零)。但是如果
x
i
x_i
xi 状态转收益不具有最优子结构,不转还是超时。(遗憾的是,我赛时没有注意到前者的问题,以下给一个 hack)
5 3 50
15 1 33
29 1 43
19 1 35
47 1 50
10 1 32
其实已经接近正解了。既然
x
i
x_i
xi 只用于
i
i
i 的前几项,
c
i
c_i
ci 用于
i
i
i 的后几项,那么就进行前缀和后缀
d
p
dp
dp,具体地,
g
(
i
,
j
)
g(i,j)
g(i,j) 表示
[
i
,
n
]
[i,n]
[i,n],花
j
j
j 的哞尼的最大受欢迎度,
f
(
i
,
j
)
f(i,j)
f(i,j) 表示
[
1
,
i
]
[1,i]
[1,i],花
j
j
j 的冰激凌甜筒的最大受欢迎度。整合答案时别忘了特别算一下中间部分优惠的一项。
code
T3 禅与园林艺术
TAG:抽屉原理,前缀和
思维题,赛时没想出来,打了暴力。
首先处理前缀和。发现本题特性模数
p
p
p 特别小,进一步通过抽屉原理想到:如果
r
−
l
+
1
>
p
r-l+1 > p
r−l+1>p,那么必然存在
s
u
m
i
′
=
s
u
m
j
′
(
m
o
d
p
)
sum_{i'}=sum_{j'} (mod\;p)
sumi′=sumj′(modp) 那么最小值就是
0
0
0。其他暴力很快求出。
code
T4 心理学概论
TAG:线段树
非常不错的题,唯独数据不合理,能卡掉
O
(
n
2
log
n
)
\mathcal{O(n^2 \log n)}
O(n2logn) 的线段树,但是最优化剪枝暴力可以满分。赛时写的是
O
(
n
2
log
n
)
\mathcal{O(n^2 \log n)}
O(n2logn) 的,但是统计答案不完全导致只有九分(为什么有wa但评测机就以tle一概而过以致我没第一时间意识到错误)。
其实我的算法也已经算半个正解了。首先按
a
i
a_i
ai 排序,枚举
a
i
a_i
ai,比当前
a
i
a_i
ai 小的都选到
A
A
A,其余进入
B
o
r
C
B\;or\;C
BorC。这里我就是建立以
b
i
b_i
bi 为下标,
c
i
c_i
ci 为值的线段树,再枚举
b
i
b_i
bi ,将
∀
b
j
≤
b
i
\forall\; b_j\leq b_i
∀bj≤bi 放入
B
B
B,其余放入
C
C
C。
这里第一步是合理的,枚举
b
i
b_i
bi 处可以进一步优化。首先我们希望答案可以成为线段树的一部分,更新线段树也要在
O
(
log
n
)
\mathcal{O(\log n)}
O(logn) 内实现。单调性是一个很好的性质,考虑到
m
a
x
c
i
=
m
a
x
j
∈
[
i
,
n
]
c
j
max\;c_i = max_{j\in [i,n]}c_j
maxci=maxj∈[i,n]cj 为后缀,而此后缀具有单调性,所以构造线段树,在
b
i
b_i
bi 下标处存
m
a
x
j
∈
[
i
,
n
]
c
j
max_{j\in [i,n]}c_j
maxj∈[i,n]cj 和
r
e
s
=
b
i
+
m
a
x
j
∈
[
i
+
1
,
n
]
c
j
res=b_i+max_{j\in [i+1,n]}c_j
res=bi+maxj∈[i+1,n]cj,再存一个
b
i
b_i
bi 方便运算。由于
m
a
x
j
∈
[
i
,
n
]
c
j
max_{j\in [i,n]}c_j
maxj∈[i,n]cj 单调不升,故单次修改二分找到最后一个
x
≥
c
i
x\geq c_i
x≥ci,修改
[
x
+
1
,
b
i
−
1
]
[x+1,b_i-1]
[x+1,bi−1] 为
c
i
c_i
ci(显然,当
x
x
x 不存在,或
x
>
b
i
−
1
x>b_i-1
x>bi−1 时不更新)。建议离散化,不建议动态开点线段树,因为后者对空下标不好处理。
code
总结
赛时期望得分: 100 + 100 + 20 + 20 = 240 100+100+20+20=240 100+100+20+20=240,实际得分 9 + 71 + 27 + 9 = 116 9+71+27+9=116 9+71+27+9=116。第一题理解题意有误,第二题写了假的,第三题暴力似乎挺快,第四题答案不完全统计。
9/6 DAY 2
合理的比赛,但第一题写炸。赛时码
T1 毒瘤计数题
TAG:组合数学
数学题,很简单推式子计算,但就是这样我也能写炸。
不多赘述,直接式子:
∑
i
∈
[
1
,
n
−
1
]
2
i
−
1
(
2
n
−
i
−
1
)
=
(
n
−
1
)
2
n
−
1
+
1
−
2
n
−
1
\sum_{i\in [1,n-1]}{2^{i-1}(2^{n-i}-1)}=(n-1)2^{n-1}+1-2^{n-1}
i∈[1,n−1]∑2i−1(2n−i−1)=(n−1)2n−1+1−2n−1 这不就是等比数列求和吗,但是赛时没看出来,算繁了,然后呢,中间用
n
n
n 代替
n
−
1
n-1
n−1,最后还没有换回来。而且,输出用快写没有
0
0
0 特判。导致痛失
90
90
90 分。
code
T2 普通图论题
TAG:树形dp
客观上,这题让我感受到了学校 oj 的神奇:同样的代码,两次提交,时间上可以差
20
%
20\%
20%,如下图:
做法树
d
p
dp
dp。首先记录
u
u
u 节点子树中的最短距离,然后再通过
d
p
dp
dp 推出非子树中的最短距离,其实后者如果站在父亲的位置就很容易看出来了,维护前者的最小和次小值就可以推出后者了。
有概率被卡常的 code
T3 简单数据结构题
TAG:线段树,构造
其实一开始想正解是完全没思路的,甚至我看到正解时都不敢相信。
从简单的开始分析:首先考虑一种
O
(
q
n
)
\mathcal{O(qn)}
O(qn) 的暴力,就是无脑地把所有区间在数轴上标出来,然后遍历互斥关系。接着,就是考虑到是静态二维问题,联想到惯用套路:二维数点。一对互斥关系可以看作两对平面上的点(正反两对),然后区间就是平面上
k
2
k^2
k2 个矩形,若矩形内有点则有互斥关系。举个例子:
x
,
y
x,y
x,y 互斥,则在平面上记
(
x
,
y
)
(
y
,
x
)
(x,y)\;(y,x)
(x,y)(y,x),然后
∀
i
,
j
∈
[
1
,
k
]
\forall i,j\in[1,k]
∀i,j∈[1,k],矩形两个对顶点(大概是这样叫的?)为
(
q
l
i
,
q
l
j
)
(
q
r
i
,
q
r
j
)
(ql_i,ql_j)\;(qr_i,qr_j)
(qli,qlj)(qri,qrj)。复杂度为
O
(
∑
k
2
log
n
)
\mathcal{O(\sum{k^2}\log{n})}
O(∑k2logn)。
这两种解法仔细想想发现截然不同,尤其是复杂度上,差异很大,便可在此做文章。前者
O
(
q
n
)
=
O
(
∑
k
k
n
)
\mathcal{O(qn)=O(\frac{\sum{k}}{k}n)}
O(qn)=O(k∑kn) ,后者
O
(
∑
k
2
log
n
)
=
O
(
k
∑
k
log
n
)
\mathcal{O(\sum{k^2}\log{n})=O(k\sum{k}\log{n})}
O(∑k2logn)=O(k∑klogn)。
∑
k
k
n
+
k
∑
k
log
n
≥
2
∑
k
⋅
n
log
n
=
⟺
k
=
n
log
n
\frac{\sum{k}}{k}n+k\sum{k}\log{n}\geq 2\sum{k}\cdot \sqrt{n\log{n}}\\ =\iff k=\sqrt{\frac{n}{\log{n}}}
k∑kn+k∑klogn≥2∑k⋅nlogn=⟺k=lognn 所以,原来单次询问中的
k
k
k 存在阈值,并可以采取不同策略(没想到暴力也是正解的一部分)。总复杂度似乎常数不大可以过,事实也是卡一下就可以。
实现要卡常不算简单,这里学了表示前缀和的线段树的构造方法,很有启发,详情见代码。
题外话,这题算不算毒瘤?
code
总结
赛时期望得分:
100
+
(
90
…
100
)
+
20
=
(
210
…
220
)
100+(90\dots100)+20=(210\dots 220)
100+(90…100)+20=(210…220),实际得分
10
+
80
+
20
=
110
10+80+20=110
10+80+20=110。第一题算得不清楚而且答案
0
0
0 快写输出没有特判,第二题没有用链式前向星,并且实现方法常数太大(这个其实是预料之中,实在不敢确定改得对,而且事实证明,多试几次就可以顺利通过评测机xd)。第三题有点毒瘤
9/9 DAY 3
T1 String Master
TAG:dp
终于,我拿满了第一题的分。挺简单的,纯的
d
p
dp
dp,不多说了。(代码看上面赛时码)
T2 平均数
TAG:二分,归并排序
因为小数不足四位没有补零而暴力一分未得。感觉赛时二分分治都想过了,就是没想到怎么转化。
首先求第
k
k
k 小第一反应是分治,但是这个似乎想不通,只好进而考虑二分:二分平均数,求平均数比它小的区间有多少。然后 check 就不会写了。其实就是转化,遇到平均数想到可以算出每个数和平均数的偏离程度(就是差值),然后看有多少区间的和是负的,然后前缀和再逆序对。所以总复杂度为二分 + 求逆序对 =
O
(
n
log
n
log
a
m
a
x
)
\mathcal{O(n\log{n}\log{a_{max}})}
O(nlognlogamax)。
code
T3 Tourist Attractions
TAG:图论,bitset
bitset
复杂度为
O
(
n
w
)
\mathcal{O(\frac{n}{w})}
O(wn),所以用此存图。
a
n
s
=
∑
(
d
e
g
i
−
1
)
⋅
(
d
e
g
j
−
1
)
−
∣
S
∣
ans=\sum{(deg_i-1)\cdot(deg_j-1)-|S|}
ans=∑(degi−1)⋅(degj−1)−∣S∣。其中
∣
S
∣
|S|
∣S∣ 表示
i
i
i 和
j
j
j 可以共同到达得点数。
code
T4 Walk
TAG:图论建模
难点一是建图。
∃
E
d
g
e
(
i
,
j
)
⟺
v
a
l
i
&
v
a
l
j
=
v
a
l
j
\exist\;Edge(i,j)\iff val_i \;\&\; val_j=val_j
∃Edge(i,j)⟺vali&valj=valj,可以理解二进制下
v
a
l
j
val_j
valj 是
v
a
l
i
val_i
vali 的子集。枚举每个权值向它的所有子集建边太复杂,考虑去简化。假如以每个权值为点,要满足子集关系,可以想到是向在二进制下仅一位的
1
1
1 改为
0
0
0 的点建边(如
0110
→
0100
o
r
0110
→
0010
0110\to0100\;or\;0110\to0010
0110→0100or0110→0010),则一个点最多
20
20
20 条边,经过多条边即可满足关系。即过程为真实点层到虚拟点层再到真实点层,甚至如此多次重复。真实点出发的边权值为
1
1
1,从权值点出发的边权为
0
0
0。总边数
∑
i
∈
[
1
,
19
]
(
20
−
i
)
(
20
i
)
≈
1
e
7
\sum_{i\in[1,19]}{(20-i){20\choose i}}\approx 1e7
∑i∈[1,19](20−i)(i20)≈1e7。
难点二是虚拟建边然后跑
O
(
m
)
\mathcal{O(m)}
O(m) 的搜索。虚拟建边二进制随便搞搞(如 lowbit)就能在过程中
O
(
1
)
\mathcal{O(1)}
O(1) 推出。搜索因为权值为
0
o
r
1
0\;or\;1
0or1,所以可以按照 dijkstra 的思路用 deque
优化(因为 priority_queue
的复杂度大)。
这样一看其实代码不难,重在思维。
code
总结
赛时期望得分: 100 + 40 + 70 + 40 = 250 100+40+70+40=250 100+40+70+40=250,实际得分 100 + 0 + 0 + 40 = 140 100+0+0+40=140 100+0+0+40=140。第二题输出去小数末尾 0 评测机不算对,第三题写了假(思维古怪)。感觉偏简单题都没搞出来,挺可惜的。
9/17 Day 4
最近有点生病,而且题目都不难,故不写题解了。赛时码+订正码
标签:搜索,kmp,dp,图论建模,最短路
总结
期望得分: 80 + 30 + 100 = 210 80+30+100=210 80+30+100=210。实际得分: 100 + 27 + 69 = 196 100+27+69=196 100+27+69=196。第一题似乎读入量大,而导致本地可以构造超时数据,但评测机似乎给过了。第二题分差应该是分值分布不均。第三题数组开小了。由于第二题涉及 kmp,故场上没写出正解,赛后学习 kmp。
9/20 Day 5
或许算是比较难的比赛?无赛时码。
T1 堆
标签:dp,剪枝,分块打表
数据 1 0 9 10^9 109 的规模首先想到推结论,然而这题却是完完全全的 d p dp dp,使用 O ( n 1000 log n ) \mathcal{O(\frac{n}{1000}\log n)} O(1000nlogn) 的算法通过。 f ( x ) f(x) f(x) 表示 x x x 个元素的二叉堆的方案数,得到转移 f ( x ) = f ( L ) ⋅ f ( R ) ⋅ ( n − 1 L ) f(x)=f(L)\cdot f(R)\cdot {n-1\choose L} f(x)=f(L)⋅f(R)⋅(Ln−1) ( L , R L,R L,R 分别表示左右子树的节点数)。不是很直观,但是可以参考解决全排列大小关系的思路,如 At_dp_t Permutation,大小关系是相对的,然后就可以理解转移方程了。直接转移可以得到 O ( n ) \mathcal{O(n)} O(n) 的算法,可以 60 p t s 60pts 60pts。
继续优化:一、因为每一个完全二叉树根的两个子树至少一个是满二叉树,所以可以预处理满二叉树,时间上为 O ( log n ) \mathcal{O(\log n)} O(logn),但想通过 1 0 9 10^9 109 的规模在空间上仍不可。二、优化阶乘打表,就是隔开大概 1 0 6 10^6 106 个数(隔得少代码太长)打表,时间上变为 O ( n 1000 log n ) \mathcal{O(\frac{n}{1000}\log n)} O(1000nlogn) 可过。
T2 密文
标签:构造,图论建模,mst,位运算,trie
询问为 p r e r ⊕ p r e l − 1 pre_r\oplus pre_{l-1} prer⊕prel−1, p r e 0 = 0 pre_0=0 pre0=0 已知,希望知道 ∀ p r e i , i ∈ [ 0 , n ] \forall pre_i,i\in[0,n] ∀prei,i∈[0,n]。抽象为 通过如何方式知道若干条 p r e x ⊕ p r e y pre_x\oplus pre_y prex⊕prey,可以通过 p r e 0 pre_0 pre0 求出 p r e i , i ∈ [ 0 , n ] pre_i,i\in[0,n] prei,i∈[0,n],其中若将 p r e x ⊕ p r e y pre_x\oplus pre_y prex⊕prey 视为 x ↔ y x\leftrightarrow y x↔y 的边,知道一个端点就能知道另一个,故转化为最小生成树,模板 Xor-MST。实现为构造 trie,树上左右儿子皆有的点 ⟺ \iff ⟺ 两个点的 lca,故对于这些点,求 m i n i ∈ l s , j ∈ r s p r e i ⊕ p r e j min_{i\in ls,j\in rs}{pre_i\oplus pre_j} mini∈ls,j∈rsprei⊕prej,而字典树中叶子节点表示的数从左至右有单调性,故枚举一个子树,然后到另一个子树匹配异或最小的数。复杂度 O ( n log n log a i ) \mathcal{O(n\log n\log a_i)} O(nlognlogai),可过。
T3 树
标签:树哈希,树的重心,dp
9/23 Day 6
小丑比赛。赛时码+订正码
T1 brick
标签:dp
很好想的 d p dp dp,但是有一些细节。 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示 i i i 列 j j j 行用了 k k k 发子弹的最大收益。可以推到 f ( i , j + 1 , k + 1 ) f(i,j+1,k+1) f(i,j+1,k+1) 或 f ( i + 1 , n , k ) f(i+1,n,k) f(i+1,n,k)。但是可能打完后剩一发,所以希望遇到可以最后打的砖块后将有奖励的砖块的要求从 k ′ < k k'<k k′<k 变为 k ′ ≤ k k'\leq k k′≤k,故再记一位,表示是否遇到可以最后打的砖块(即打完无奖励,直接换到下一列),但要注意不能一次都不打就转到上述第二位,我就是这里没有初始化错的。
赛时期望得分 100 100 100,实际 40 40 40。
T2 math
标签:数学,递推
很简单的想法,略复杂的运算。推式子: f ( i ) = a i + b i + c i , g ( i ) = a b i + a c i + b a i + b c i + c a i + c b i f(i)=a^i+b^i+c^i,\;g(i)=ab^i+ac^i+ba^i+bc^i+ca^i+cb^i f(i)=ai+bi+ci,g(i)=abi+aci+bai+bci+cai+cbi,则有 a b c = f 3 ( 1 ) − f ( 3 ) − 3 ∗ g ( 2 ) 6 abc=\frac{f^3(1)-f(3)-3*g(2)}{6} abc=6f3(1)−f(3)−3∗g(2),然后 f ( i ) = f ( 1 ) f ( n − 1 ) − g ( i − 1 ) , g ( i − 1 ) = f ( i − 2 ) ⋅ g ( 1 ) 2 − a b c ⋅ f ( i − 3 ) f(i)=f(1)f(n-1)-g(i-1),\;g(i-1)=f(i-2)\cdot\frac{g(1)}{2}-abc\cdot f(i-3) f(i)=f(1)f(n−1)−g(i−1),g(i−1)=f(i−2)⋅2g(1)−abc⋅f(i−3)。
赛时期望得分
100
100
100,实际得分
40
40
40。原因:operator
在结构体中直接引用自己的内容会修改其值。
T3 xor
标签:trie,位运算
很简单的 T3, l o w b i t ( x ⊕ y ) lowbit(x\oplus y) lowbit(x⊕y),即 x , y x,y x,y 二进制下最小的不同位,考虑二进制构建 trie,这样可以一层层枚举当前位为最小的不同位,类似线段树的统计。
赛时期望得分 100 100 100,实际得分 40 40 40,原因:常数太大,导致有概率被评测机卡了,比如赛时 1002ms,赛后 893ms,然后 subtask 又是捆绑的,故得分低,好气哟!!!!!