折半搜索
当看到n非常小的时候,一般是(25~40),想暴力但是会T,这时候就可以想一想是否需要折半搜索
主要步骤有2个:
1.搜前一半,存答案
2.搜后一半,得到的结果和前一半去匹配
一般来说搜索只需要最普通的dfs即可,而存答案多和stl有关
经典例题:
L
i
g
h
t
s
w
i
t
c
h
e
s
Light\; switches
Lightswitches(如果对半分容易T,那么预处理的时候多处理一点,处理20个,剩下在询问的时候处理即可)
X
o
r
−
P
a
t
h
s
Xor-Paths
Xor−Paths(显然在对角线处分开,这里处理的时候要记一下:当
x
+
y
=
=
(
n
+
m
)
/
2
+
1
x+y==(n+m)/2+1
x+y==(n+m)/2+1的时候,
(
x
,
y
)
(x,y)
(x,y)就是对角线上的点了)
M
a
x
i
m
u
m
S
u
b
s
e
q
u
e
n
c
e
Maximum \;Subsequence
MaximumSubsequence(首先先把所有数字对m取模,然后求出前一半所有可能的和,后一半所有可能的和,设前一半的一个值为x,则在后一半里找比m-x小的第一个数即可)
L
i
z
a
r
d
E
r
a
:
B
e
g
i
n
n
i
n
g
Lizard \;Era: Beginning
LizardEra:Beginning(枚举每个工作要分给哪些人,并用三进制状压记录方案就ok了,但是注意,在输出方案的时候,有最后一位对应的就是0,所以直接while(x)是不对的,应该给出明确的循环次数)
分治
类似于线段树的操作,处理一个区间的时候,把他分成两部分,每部分再按同样的方式进行处理(但是感觉没啥特征)
O
p
t
i
m
a
l
I
n
s
e
r
t
i
o
n
Optimal\;Insertion
OptimalInsertion(首先把b排序,能保证,对于b来说,贡献是0,逆序对最小,接着考虑b插入的顺序,找到b[mid],判断哪里逆序对最少,插进去后,a,b两个区间都被分成了两部分。mid前的数只能再往前面插,这样处理,时间复杂度就变成log了)
T
h
e
N
u
m
b
e
r
o
f
S
u
b
p
e
r
m
u
t
a
t
i
o
n
s
The\;Number \;of \;Subpermutations
TheNumberofSubpermutations(求排列的个数。可以从整段区间的最大值写起。找到最大值,这个可能的排列的长度就确定了,剩下的就是判断是否合法。当这个最大值处理完之后,剩下的排列都不能包含它了,所以就把区间分成两部分,然后重复操作。)
(但是判断是否合法的过程又很费时间,所以我用一个数组wz,记录有相同的值最靠近它出现的位置,比如1 2 2 1,的数组就是 0 0 2 2。枚举端点,如果wz[r]<l,说明在这一段区间内是没有相同的数字的,又因为我们当前考虑的是这段区间的最大值,所以这段区间内的数都是<=这个数,且不重复的,因此构成了一个排列)这点技巧可以掌握一下
0,1,-1转化
在求方案,可行性,反正就是和取值没有什么太大关系的时候,可以用0,1,-1代替原数,这样处理起来就会非常方便
经典例题:
T
e
l
e
p
h
o
n
e
L
i
n
e
s
Telephone Lines
TelephoneLines(二分+最短路)(判断的时候,可以选取适当的参考,用0,1,-1代替原数,这样就可以用最后求出来的结果
O
(
1
)
O(1)
O(1)判断是否合法了)
例:
c
o
e
x
i
t
coexit
coexit(把0改成-1,进行前缀和操作)
M
i
l
k
V
i
s
i
t
s
S
Milk Visits S
MilkVisitsS(这是一道lca的题,但是也是用01求答案,而且是我根本没看题解,自己码出来的(不容易啊),所以值得放上来)
整理书架(线段树+ -1,1标记)
冒泡排序(和上面竟然是一个思想!考的时候完全想不起来)
【bzoj3697】采药人的路径(把0变成-1,满足阴阳平衡只需要路径和为0就好了)
模型转换
E x t e n d i n g S e t o f P o i n t s Extending\;Set\;of\;Points ExtendingSetofPoints
原题:在一个网格图中,如果(a,b),(a,y),(x,b)存在于集合中,那么(x,y)自动加入,直到加不下去,每次进行加点,删点操作,求每次的集合大小
转化:有两列数,一列为横坐标,一列为从坐标,把(a,b)看成a->b的边,若存在边(a,b),(a,y),(x,b),那么(x,y)自动连边,求总边数。可以发现,每次a向对面连的所有点,都会和b向对面连的所有点连边,设左边总点数为L,右边为R,那么答案就是L*R
摆棋子
原题:n*m的网格上,每个格子只能放一个棋子,有些不能放,每行每列都有一个限制,至少放那么多棋子,求最小需要的棋子数
转化:建立网络流模型
先把问题反转,求最多能省下多少个位置不放棋子,最后减一下即可
将每一行,每一列变成n+m个点,源点向表示行的点连边,容量为(每行空着的数量-需要的棋子数),若点(i,j)能放棋子,那么i向j+n连容量为1的边,列向汇点连边(同行),跑一遍最大流即可
图腾
原题:在 k 维空间中,如果 k+1 个整点 A0,A1,…,Ak 满足:
A0 的每一维坐标都是偶数
对于任意 0≤i<j≤k 都有 Ai 与 Aj 的欧几里得距离为
j
−
i
\sqrt{j-i}
j−i
就称这 k+1 个点构成图腾。
现有 n 个整点 P1,P2,…,Pn ,你希望删去其中一些点使得剩余的点中任何 k+1 个都不构成图腾,问最少删多少点。
转化:建立最小割模型
题目可以发现,在一个图腾内,相邻的两个点一定是k位中只有一位差了1,所以A0一定都是偶数,那么Ak一定都是奇数。
我们对于每一个点,都去找和他只有一位差1的,连一条容量为maxx的边,源点向符合起点条件的连容量为maxx边,符合终点条件的向汇点连容量为maxx边,而对于每一个点,我们进行拆点,中间流量为1,表示切断这条边的代价是1,其实也就相当于删了这个点,然后求最小割就行了
D Z Y L o v e s C h i n e s e I I DZY \;Loves\; Chinese\; II DZYLovesChineseII
原题:给一个图,每次删k条边(每次询问独立),问删完之后是否联通
转化:利用线性基性质解答
先随便找出一棵树,给树边赋上随机权值(随机的时候尽量大),然后非树边的权值等于两端点树上权值的异或和,把删除的边的权值尝试插入线性基,如果失败,表示把这个环都删了,那么就不连通了
正难则反
经典例题:
F
a
r
m
U
p
d
a
t
e
s
G
Farm\; Updates\;G
FarmUpdatesG(正着做是把连通块断开,反着就变成不断合并联通块了,并查集的操作)
旅行路线(将图反过来就变成一棵树了)
对象转化
将计算有多少个,转化成当前这个对总答案的贡献是多少
经典例题:
m
a
t
r
i
x
matrix
matrix
求x为次大值的最大区间
这样的最大区间有两个,一个是(左边第二个大于它的,右边第一个大于它的),另一个是(左边第一个大于它的,右边第二个大于它的),两个都是开区间。
此时可以用链表来解决,用
p
e
r
,
n
x
t
per,nxt
per,nxt表示左边第一个比他大的位置,右边第一个比他大的位置,刚开始赋成
i
−
1
,
i
+
1
i-1,i+1
i−1,i+1,然后把值排个序,按照顺序删除元素,同时查找,那么比它小的数都被删了,
p
r
e
,
n
x
t
pre,nxt
pre,nxt自然会进行一些移动得到的这个结果就是要找的了,这么说可能有些模糊,意会一下
经典例题:
A
l
o
Alo
Alo