文章目录
(据说是)鏼爷神题
Day1
T1 回文切割(pal)
题目大意: 给定一个长为
n
n
n(
n
n
n是偶数)的01串
s
s
s,我们要反转里面的几位,使得这个01串能由若干偶数长度的回文串连接而成,反转第
i
i
i位的代价是
w
i
w_i
wi,求最小代价。
n
≤
2000
n\le 2000
n≤2000。时限
2
s
2s
2s。
做法: 本题需要用到DP。
显然有区间型DP的思路,令
f
(
i
)
f(i)
f(i)为使长为
i
i
i的前缀满足条件的最小代价,则有:
f
(
i
)
=
min
{
f
(
j
)
+
w
(
j
+
1
,
i
)
}
f(i)=\min\{f(j)+w(j+1,i)\}
f(i)=min{f(j)+w(j+1,i)}
现在的问题就是如何求
w
(
l
,
r
)
w(l,r)
w(l,r):使
[
l
,
r
]
[l,r]
[l,r]一段为回文串的最小代价。
显然偶回文串一定有一个对称轴,在中间的两个数之间。为了让它们回文,那么应该使第
l
l
l位和第
r
r
r位相等,第
l
+
1
l+1
l+1位和第
r
−
1
r-1
r−1位相等…那么最小代价就是,如果对应的两个位置当前不等,就要更改其中代价较小的一个。但是,如果我们固定
l
l
l,枚举
r
r
r来计算,会发现非常难算,需要
O
(
n
3
)
O(n^3)
O(n3),但如果改成枚举对称轴计算就会非常简单了,时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),DP的复杂度也是
O
(
n
2
)
O(n^2)
O(n2),我们就解决了这一题。
T2 模(mod)
题目大意: 给定一个集合
S
S
S,内含
n
n
n个非负整数
a
i
a_i
ai,
q
q
q个询问,每次询问给出一个质数
p
p
p和
r
(
0
≤
r
<
p
)
r(0\le r<p)
r(0≤r<p),询问集合
S
S
S有多少个子集,使得子集内元素的乘积对
p
p
p取模的结果是
r
r
r。空集乘积算作
1
1
1。
q
≤
5
,
n
≤
35
,
p
≤
1
0
9
q\le 5,n\le 35,p\le 10^9
q≤5,n≤35,p≤109。时限
4
s
4s
4s。
做法: 本题需要用到折半+map+逆元。
由于询问数很小,可以直接当作多组数据处理。如果看到了部分分的话,50分的范围是
n
≤
18
n\le 18
n≤18,这显然就可以二进制枚举暴力计算了。而全部的数据范围是
n
≤
35
n\le 35
n≤35,这就提示了我们利用折半的思想,把集合拆成两个大小分别为
17
17
17和
18
18
18的集合。对于大小为
18
18
18的集合,暴力枚举,在map中存储乘积模
p
p
p为
b
b
b的子集的个数。然后再枚举大小为
17
17
17的集合中的子集,假设这个子集的乘积模
p
p
p为
a
a
a,我们要求出所有满足
a
b
≡
r
(
m
o
d
p
)
ab\equiv r(\mod p)
ab≡r(modp)的
b
b
b来累加答案。显然,因为
p
p
p是质数,所以满足要求的
b
b
b有且仅有
1
1
1个,直接算出
a
a
a的逆元再乘
r
r
r就是了,直接在map中查找即可。于是时间复杂度为
O
(
2
17
⋅
(
18
+
log
p
)
)
O(2^{17}\cdot (18+\log p))
O(217⋅(18+logp)),可以通过此题。
Day2
T1 数列(sequence)
题目大意:
q
q
q次询问,每次给定
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d,求以下数列:
x
0
=
c
,
x
i
=
a
x
i
−
1
+
b
x_0=c,x_i=ax_{i-1}+b
x0=c,xi=axi−1+b中,编号最小的
≥
d
\ge d
≥d的一项的编号,如果不存在输出
−
1
-1
−1。
q
≤
5000
,
∣
a
∣
,
∣
b
∣
,
∣
c
∣
,
∣
d
∣
≤
1
0
9
q\le 5000,|a|,|b|,|c|,|d|\le 10^9
q≤5000,∣a∣,∣b∣,∣c∣,∣d∣≤109。
做法: 本题需要用到分类讨论。
分类讨论神题。根据正常高中数学推理,得到数列的通项公式:
x
i
=
(
c
+
b
a
−
1
)
⋅
a
i
−
b
a
−
1
(
a
≠
1
)
x_i=(c+\frac{b}{a-1})\cdot a^i-\frac{b}{a-1}(a\ne 1)
xi=(c+a−1b)⋅ai−a−1b(a=1),数列有四种可能的增长情况:循环
(
a
=
0
,
−
1
)
(a=0,-1)
(a=0,−1),单调增,单调减,或者上下波动(
a
<
−
1
a<-1
a<−1)。其他的就直接计算或者二分即可,最麻烦的情况是上下波动,它会呈现奇数项单调增,偶数项单调减(或者相反)的状态,再分类讨论一下二分即可。
(什么毒瘤题啊…完全不想动手写…)
T2 子集和(subsetsum)
题目大意: 给定一个数列
A
A
A,定义一个数列
A
A
A是好的,当且仅当对于所有
1
≤
t
≤
∑
A
i
1\le t\le \sum A_i
1≤t≤∑Ai,都存在一个子集
S
⊆
A
S\subseteq A
S⊆A,使得
t
=
∑
S
i
t=\sum S_i
t=∑Si。问数列
A
A
A有多少个非空的子数列(不一定连续,所以一共有
2
n
−
1
2^n-1
2n−1个)是好的。
n
,
A
i
≤
5000
n,A_i\le 5000
n,Ai≤5000。时限
2
s
2s
2s。
做法: 本题需要用到DP。
考虑贪心地判断一个数列是不是好的。由于我写过FJOI神秘数那题,因此思路很明显:先将数列从小到大排序,如果存在一个
A
i
A_i
Ai,使得
A
i
>
1
+
∑
j
=
1
i
−
1
A
j
A_i> 1+\sum_{j=1}^{i-1}A_j
Ai>1+∑j=1i−1Aj,则数列就不是好的,如果不存在这样的
A
i
A_i
Ai,数列就是好的。简单证明一下就是,在到这样的
A
i
A_i
Ai之前,数列都是好的,但是加入
A
i
A_i
Ai后,
(
∑
j
=
1
i
−
1
A
j
,
A
i
)
(\sum_{j=1}^{i-1}A_j,A_i)
(∑j=1i−1Aj,Ai)这一段开区间就无法表示了,而又因为后面的
A
x
A_x
Ax都比
A
i
A_i
Ai大,因此这一段开区间永远都不可能被表示出来了,所以数列就不是好的,否则它就是好的。
这样一来,我们显然把整个数列从小到大排序,然后令
f
(
i
,
j
)
f(i,j)
f(i,j)为最大的元素为
A
i
A_i
Ai的元素和为
j
j
j的好的子数列数目,有:
f
(
i
,
j
)
=
∑
k
=
1
i
−
1
∑
p
+
1
≥
j
f
(
k
,
p
)
f(i,j)=\sum_{k=1}^{i-1}\sum_{p+1\ge j}f(k,p)
f(i,j)=∑k=1i−1∑p+1≥jf(k,p)
显然当
j
>
A
n
j>A_n
j>An时,具体的
j
j
j值已经没有意义了(因为它可以被算作任何后面元素的贡献了),这时候直接令
j
=
A
n
+
1
j=A_n+1
j=An+1即可。于是用前缀和优化就可以做到
O
(
n
A
n
)
O(nA_n)
O(nAn)的时间复杂度了。
T3 棋盘(board)
题目大意: 一个
n
×
m
n\times m
n×m的棋盘,上面一些格子已经被涂成红色或黑色,现在要给其他的格子涂上红色或黑色,使得任意位于同一行或同一列的三个连续格子不被涂上相同的颜色,求方案数。
n
,
m
≤
11
n,m\le 11
n,m≤11。时限
5
s
5s
5s。
做法: 本题需要用到状压DP。
容易想到按行状压DP,但是状态数看上去海量,直接暴做复杂度不可算,因此我们要精简状态。
首先从每一行的状态入手。暴力枚举的话,它会有
2
m
2^m
2m个状态。但鉴于可能有很多状态是不满足连续三格不涂同一颜色的条件的,我们考虑预处理排除掉不满足这个条件的状态。那么在合法状态中,颜色肯定是由长为
1
1
1或
2
2
2的连续段形成的,对于一种划分方案,有
2
2
2种涂色方式(第一段涂红色或黑色),而这样的划分方案数是一个经典的问题,答案是斐波那契数列的第
m
m
m项(前两项为
1
,
2
1,2
1,2时),
F
11
=
144
F_{11}=144
F11=144,因此合法的状态数最多有
288
288
288个,比
2
11
=
2048
2^{11}=2048
211=2048少了很多。
又因为每行的状态只有
288
288
288个,而DP时只要考虑上面两行的状态即可判断是否满足条件,因此DP的时间复杂度应该是
O
(
n
⋅
28
8
3
⋅
m
)
O(n\cdot 288^3\cdot m)
O(n⋅2883⋅m),算出来有
3
e
9
3e9
3e9这么大,肯定过不了。我们发现问题在于判定条件合法一次是
O
(
m
)
O(m)
O(m)的,能不能更快呢?这时候就要用位运算来强凑了。
首先一个问题是,如何快速判断当前状态在某些位上等于某些数?令当前状态为
x
x
x,为了提取出固定的位,我们定义一个数
y
y
y为,如果某一位被限制,这一位就是
1
1
1,否则就是
0
0
0,这样一个数,那么
x
a
n
d
y
x\space and \space y
x and y就是
x
x
x被提取出的那些位的数了。而
z
z
z定义为如果某一位被限制,这一位就是被限制要成为的数,否则就是
0
0
0,这样一个数,那么当且仅当
x
a
n
d
y
x\space and \space y
x and y和
z
z
z完全相同时,条件被满足,于是异或一下判断是不是
0
0
0即可。
然后一个问题是,有了连续三行的状态
x
,
y
,
z
x,y,z
x,y,z,如何判断存不存在某一位上全是
0
0
0或者
1
1
1?注意到,如果一位全是
0
0
0或
1
1
1,那么这一位上三个数
a
n
d
and
and和
o
r
or
or的结果应该是相同的,否则就不同,因此我们将
x
a
n
d
y
a
n
d
z
x\space and \space y\space and\space z
x and y and z和
x
o
r
y
o
r
z
x\space or \space y\space or\space z
x or y or z异或起来,如果它等于
2
m
−
1
2^m-1
2m−1(也就是全是
1
1
1),就说明不存在某一位上全是
0
0
0或
1
1
1。
这样我们就可以
O
(
1
)
O(1)
O(1)(计算机中的)判断条件是否满足了,那么优化过的复杂度经过计算是
2.6
e
8
2.6e8
2.6e8,
5
s
5s
5s的时间限制下也许能过,有时间写写试试吧…
Day3
T1 海龟(turtle)
题目大意: 在一个网格图上,有一只海龟要顺次经过
n
n
n个整点,行走的过程是走直线,问行走过程中一共经过多少个整点,重复经过不重复计算。
n
,
x
,
y
≤
1000
n,x,y\le 1000
n,x,y≤1000。
做法: 本题需要用到找规律+模拟。
我们找到一个规律:在两个整点
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
(x_1,y_1),(x_2,y_2)
(x1,y1),(x2,y2)之间的线段上,有
g
c
d
(
∣
x
1
−
x
2
∣
,
∣
y
1
−
y
2
∣
)
+
1
gcd(|x_1-x_2|,|y_1-y_2|)+1
gcd(∣x1−x2∣,∣y1−y2∣)+1个整点,它们的坐标是
(
x
1
+
k
⋅
x
2
−
x
1
g
c
d
(
∣
x
1
−
x
2
∣
,
∣
y
1
−
y
2
∣
)
,
y
1
+
k
⋅
y
2
−
y
1
g
c
d
(
∣
x
1
−
x
2
∣
,
∣
y
1
−
y
2
∣
)
)
(x_1+k\cdot \frac{x_2-x_1}{gcd(|x_1-x_2|,|y_1-y_2|)},y_1+k\cdot \frac{y_2-y_1}{gcd(|x_1-x_2|,|y_1-y_2|)} )
(x1+k⋅gcd(∣x1−x2∣,∣y1−y2∣)x2−x1,y1+k⋅gcd(∣x1−x2∣,∣y1−y2∣)y2−y1)。显然每次行走
O
(
max
x
)
O(\max x)
O(maxx)枚举
k
k
k对点标记,最后
O
(
max
x
⋅
max
y
)
O(\max x\cdot \max y)
O(maxx⋅maxy)统计即可。
Day4
T2 欧拉回路(euler)
题目大意: 有
n
n
n个点,点
i
i
i和点
j
j
j之间有边当且仅当
(
i
−
j
)
⋅
(
a
i
−
a
j
)
>
0
(i-j)\cdot (a_i-a_j)>0
(i−j)⋅(ai−aj)>0,问连出的图存不存在欧拉回路。
n
≤
1
0
5
,
T
≤
10
n\le 10^5,T\le 10
n≤105,T≤10。时限
2
s
2s
2s。
做法: 本题需要用到图论结论+树状数组。
根据图论的结论,一个图存在欧拉回路,当且仅当图中每个点的度数是偶数,并且图连通。求每个点的度数应该简单了,直接求它左边有多少个比它小的,右边有多少个比它大的即可,用树状数组+离散化做到
O
(
n
log
n
)
O(n\log n)
O(nlogn)。关键是如何判连通。
我们先证明一个引理:对于连续排列的三个连通块
A
,
B
,
C
A,B,C
A,B,C,不存在
A
,
C
A,C
A,C连通,但
A
,
B
A,B
A,B和
B
,
C
B,C
B,C间都没有边的情况。显然,根据
A
,
C
A,C
A,C连通,说明
A
A
A中存在一个元素比
C
C
C中的某元素小,也就说明
min
(
A
)
<
max
(
C
)
\min(A)<\max(C)
min(A)<max(C),而
A
,
B
A,B
A,B和
B
,
C
B,C
B,C间没有边,可以同样地看成
min
(
A
)
≥
max
(
B
)
,
min
(
B
)
≥
max
(
C
)
\min(A)\ge \max(B),\min(B)\ge \max(C)
min(A)≥max(B),min(B)≥max(C),那么
min
(
A
)
≥
max
(
C
)
\min(A)\ge \max(C)
min(A)≥max(C),所以这两个条件矛盾,因此结论成立。这也就意味着,如果图不连通的话,则必定存在一个分界点
i
i
i,使得
min
{
a
j
∣
j
≤
i
}
≥
max
{
a
j
∣
j
>
i
}
\min\{a_j|j\le i\}\ge \max\{a_j|j>i\}
min{aj∣j≤i}≥max{aj∣j>i},直接
O
(
n
)
O(n)
O(n)判定即可,这样我们就解决了这一题。
(据说是)吴凯路爷爷神题
Day4
T2 挣钱(trade)
题目大意:
n
n
n个城市连成树状图,边有长度,现在要倒卖一种物品,这种物品在城市
i
i
i的价格为
a
i
a_i
ai,选择一个城市购买一件这种物品,再走到另一个城市卖掉,走过一条长度为
x
x
x的边花费为
x
x
x,求一次能得到的最大收益。
n
≤
1
0
5
n\le 10^5
n≤105。
做法: 本题需要用到树形DP。
考虑枚举路径的LCA:
v
v
v,如何计算过这一点的路径的最大价值呢?令
d
i
s
i
dis_i
disi为点
i
i
i到
v
v
v的距离,那么答案就是子树中
a
i
−
d
i
s
i
a_i-dis_i
ai−disi的最大值加上
−
a
i
−
d
i
s
i
-a_i-dis_i
−ai−disi的最大值,这些显然都可以用树形DP很自然地维护出来。现在有的同学有疑问了,如果满足这两个最大值的两个点在
v
v
v的同一个儿子的子树中怎么办呢?当然你想去重也可以去重,但这里因为如果它路径有重,那它肯定没有LCA在另一个点的情况时优,所以我们可以直接不管去重。这样就可以
O
(
n
)
O(n)
O(n)解决这一题了。
Day5
T2 马拉松路径(path)
题目大意: 给定一张带边权无向连通图,给定一个
C
C
C个点的点集,要从里面选两个不同的点作为起点和终点,求最短路的最小值。
C
≤
n
≤
1
0
5
,
m
≤
1
0
5
C\le n\le 10^5,m\le 10^5
C≤n≤105,m≤105。时限
3
s
3s
3s。
做法: 本题需要用到最短路+二进制分组。
神仙题。
如果是规定了起点集合和终点集合,直接建超级源点和超级汇点做即可。但是这个题给的
C
C
C个点都可能作为起点或终点,还限制同一个点不能同时为起点或终点。直接枚举起点,每次做单源最短路,这和暴力没什么区别,我们需要更加优美地枚举所有可能的情况。
注意到两个点不同,一定代表着它们编号的二进制表示中,存在某一位不同。因此我们对每一个二进制位分组,是
0
0
0的分为起点集合,是
1
1
1的分为终点集合,这样就可以保证起点和终点集合不同,而这样
O
(
log
n
)
O(\log n)
O(logn)次最短路做下来一定会包含所有起点和终点的情况,这样就可以
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n)计算出答案了。