好久没做题,新开一个好了
codeforces1267G
稍微思考一下可以发现,一定是随机拿一段时间,然后把剩下的买下来
因为一个过程是随机的,另外一个过程是非随机的,因此不好讨论
观察到一定是全部买下来,因此可以把买下来的过程改为随机买一个
这样两种操作就非常对称了
要么随机拿,有一个代价。要么随机买,会有另外一个代价
稍微推到推到一下,发现两个的代价都只跟剩下物品代价的总和和个数有关
而因为每一个状态都只是在原来的基础上多买一个,因此买了k个状态只会出现一次
也就是出现的概率是
f
k
C
n
k
\frac{f_{k}}{C_n^k}
Cnkfk
先DP出剩下的代价总和为S,且总共有k的方案数,然后这一步的代价就是两个操作较小的一个就可以了
感觉把一个非随机的过程用随机的方法处理,使得操作相似度变高的思想还是挺妙的
arc115F
感觉这题好神奇啊…
先考虑这个一个事情,如果一个点要移动,他一定会移动到一个
h
h
h小于等于他的地方,记移动过程中的最大值为
m
x
mx
mx,显然是选择mx最小的来移动
可以发现,对于一个点来说,这样移动了肯定会使得后面的答案减小
但你很快又会发现,比如一个点要移动到终点,那么h值可能不得不变大
也就是说,为了到达终点,一个点的移动是一段下降的序列,然后最后走到终点
但是这样又出现了新的问题,就是你不知道一个点什么时候该继续下沉,什么时候该前往终点,因为存在有其它的点,如果太早前往终点,可能会使得别的点的代价变大。
怎么办?
我们不仅从起点开始走,同时也从终点开始走就可以了
两边谁的代价小就搜谁,因为h递减,因此两者肯定会相遇
至于h相同的情况,随便定一个第二关键字,比如说坐标就好了
codeforces1503D
这题看起来就很2-sat的样子,然后跑去认真学习了一下2-sat,到大学了,终于学会正确的2-sat姿势了
然而这题并不需要什么2-sat的姿势
观察一下,一个方案排不出来的情况,当且仅当
(
a
i
−
a
j
)
(
b
i
−
b
j
)
<
0
(a_i-a_j)(b_i-b_j)<0
(ai−aj)(bi−bj)<0
也就是同小或者同大,类似2-sat的拆为两个点,然后把矛盾点之间相互连边
可以发现,这个图不仅对称,而且高度对称,也就是连边都是双向的
直接用并查集维护出最后点集的情况
对于两团点,要么毫无关系,要么一一对立,选择不用反转多的一团就可以了
说的简单,但是由于太久没有写代码写出了一堆傻逼错误
更有趣的是,我写了个对拍
很巧地前后排出两个错误,然后不知道为什么分别改在了源代码和对拍的代码上…
然后两个代码各修复了一个bug,然而两个都不是对的
搞了半天才发现…
《论写对拍的时候把源代码从文本中删去的重要性》
牛客练习赛79E
有一个很显然的
n
p
2
np^2
np2的做法,但是状态数已经达到
n
p
2
np^2
np2,显然没有前途
对于题目所给条件
a
i
≤
b
i
a_i \le b_i
ai≤bi
也就是说,对于任意一种合法方案,都可以找到一种方案,使得对于每一个
i
i
i,存在有
a
i
≤
d
i
≤
b
i
a_i \le d_i \le b_i
ai≤di≤bi,且
∑
d
i
=
P
\sum d_i=P
∑di=P
也就是说,我们可以把所有
(
a
i
,
b
i
,
c
i
)
(a_i,b_i,c_i)
(ai,bi,ci)看作是
(
d
i
,
d
i
,
c
i
)
(d_i,d_i,c_i)
(di,di,ci),然后做背包,最后答案是
f
p
f_p
fp即可
对于每一层的
d
i
d_i
di,显然转移的是一段区间,单调队列优化就可以了
HDU 5222
突然想判断一个混合图里面有没有环,然后发现这还有一个原题
先考虑所有的无向边,用并查集维护
如果这样找不到环,就把同一个并查集里面的点缩起来,当作有向图做就可以了
codeforces1483D
一开始看错了,以为mq就可以过…然后我还在想这题为啥这么傻逼…
然后可以观察到,这题可以做qm,有可以做mq,但是交换的同时,另一部分的代价是m或q
这点和分块很像,启发我们去平衡复杂度
对于每一个询问,考虑枚举一个中间点,钦定
x
x
x走到点
i
i
i,加入一个二元组
(
i
,
y
)
(i,y)
(i,y),表示从i出发,走到y最多可以多少就可以满足条件
然后对于每一条边,同样枚举一个终点,钦定
y
y
y走到
j
j
j,然后简单用二元组查询就可以了
codeforces1483A
先把k=1的搞掉,然后每次选小的就可以了
codeforces1500C
大力猜出一个做法,以为是错的,结果发现题解跟我一样2333
主要是我当时以为每一列可能会操作多次
但其实,稍微用笔画一下就可以知道,操作多次是不存在的
假设我们现在有操作序列
x
,
y
,
x
x,y,x
x,y,x
考虑
y
y
y前面这个
x
x
x会带来什么影响
显然只会影响再
y
y
y这一列大小一样的数的相对顺序
然而如果这个相对顺序改变,显然
y
y
y后面的
x
x
x也可以达到相同的效果,也就是前面
x
x
x的作用会完全被后面所代替
这也就说明了每一列只可能会操作一次
考虑倒着构造答案
显然最后要是一列非降的我们才可以操作
操作完之后,原来的行就会被分段,每一段的数字在这一列是完全一样的,因为数字不同可以通过这一个操作排好序
分完段之后,我们的任务就变成了,只需要保证段之间的相对顺序可以复原就可以了
继续倒着走,我们接下来可以进行的操作只需要满足每一个段内都是非降的就可以操作了
一个列只要可以操作了,肯定就会进行操作,因为这样只可能会让段数增多,显然这是往答案前进的方向
先后顺序不会改变段的个数,但是显然如果是根据前面分出的段才可以操作的列显然要放在前面
最后,把所有能操作的列操作完,如果得到答案了就是输出,否则显然无解
随便维护一下就可以
O
(
n
m
)
O(nm)
O(nm)了,但是最后得到操作序列暴力排序会带一个log
codeforcesgym?
(2021.3.14F)
小数最优解的题,往往考虑通过设未知量来解决
对于这题,可以先把所有有水的地方所成一个点,然后再将所有c相连通的点缩为一个点
然后现在我们得到一个图,一共有E个未知量
对于每一个点,我们可以列出一个方程,然后对于有水的地方,他的方程就是流出去的总和为其它的总和(其实这个方程不要也可以)
也就是说我们现在得到了V个方程
考虑剩下的方程怎么凑出来
对于一个环,假设我们给他一个循环流t
那么其实代价会增加
t
∑
d
f
i
2
c
i
d
f
i
=
t
∑
2
f
i
c
i
t\sum\frac{d{f_i^2c_i}}{df_i}=t\sum 2f_ic_i
t∑dfidfi2ci=t∑2fici
换句话说,最优解里面,每一个环都要满足
∑
2
f
i
c
i
=
0
\sum2f_ic_i=0
∑2fici=0
也就是每一个环也会带来一个方程,也就是有E-V-1个方程
加上每一个点的带来的V个方程,方程已经足够
解出来就可以了
牛客练习赛78E
稍微玩一下,就相当于选两个区间拼起来
把所有合法的区间找出来,其实就是给你n个数,要你找两个数x,y
使得x&y=0,且x^y最大
直接DP出
f
i
f_i
fi表示i的存在的最大子集
那么
x
x
x,
y
y
y定属于两个不相交的集合
令所有数或起来为
m
x
mx
mx,暴力枚举一个集合
i
i
i,答案即为
m
a
x
(
f
i
+
f
m
x
⨁
i
)
max(f_i+f_{mx \bigoplus i})
max(fi+fmx⨁i)
codeforces840B
考虑把dfs树搞出来,然后每一个点通过与父亲的连边来配合d
如果有-1,直接把这个-1当作根,下面随便调整就可以了
如果没有,推到一下可以发现,如果我们选择一条不在dfs树上的边,不会对根造成任何影响
也就是暴力调整,如果根符合就符合,不符合就直接-1就可以了
codeforces840D
发现
k
k
k不超过
5
5
5,也就是说可能符合条件的数不会超过
5
5
5个,我们暴力把这些数找出来然后check一下就好了
可以发现,如果一个数出现了p次,那么把这一段区间的数从小到大排序,它一定会在
p
,
2
p
,
3
p
,
4
p
.
.
.
p,2p,3p,4p...
p,2p,3p,4p...中的某一个位置出现
用主席树暴力把这些位置的数都拿出来,check就好了
codeforces840C
把平方的因子去掉,就变成了有n种数,每一种数字不可以相邻,问方案
考虑插入法
f
i
,
j
f_{i,j}
fi,j表示现在解决了前
i
i
i种数,然后有
j
j
j对数字相邻了
转移的话,枚举一下这种数分成多少组,就可以知道它会贡献多少对相邻的数字
然后再枚举一下会插到之前多少对相邻的数字中间
然后随便搞一下就好了
看起来是
O
(
n
4
)
O(n^4)
O(n4),但感觉可以证明是不超过
O
(
n
3
)
O(n^3)
O(n3)的
gym102979G
区间dp,
f
l
,
r
f_{l,r}
fl,r表示
[
l
,
r
]
[l,r]
[l,r]的答案
比赛的时候傻逼了,把当前最大用到哪里也丢到了状态里面,即
f
l
,
r
,
k
f_{l,r,k}
fl,r,k
其实对于这种最优化问题,这种
k
k
k,是毫无必要的,因为最优的答案肯定不会说选了一个小的覆盖来累计答案
因此直接
[
l
,
r
]
[l,r]
[l,r]就足够了
暴力枚举这一段的最大值
k
k
k,直接斜率优化一波就可以了
noi2020 制作菜品
做了半天没有看到
m
>
=
n
−
2
m>=n-2
m>=n−2的条件,自闭了虽然我也没想到要讨论大小
对于
m
>
=
n
−
1
m>=n-1
m>=n−1,可以证明一定有解,并且最小配最大就可以了
用归纳法很好证明,最小的配最大,显然如果都大于k,那么一直拿肯定有解
否则最小的拿走,就会使得材料-1,需要的菜品-1,即(n-1,m-1)
(
1
,
2
)
(1,2)
(1,2)显然有解,故得证
接着考虑
m
=
=
n
−
2
m==n-2
m==n−2
把菜看作时点,材料看作是边,显然图不可能连通
即可以分为两个互不相关的子图,也就是把材料分为两堆来做
dp一下找到这两堆,然后贪心就可以了
codeforces23C
一般这种一半的,不难想到通过分组然后每一组里面都是大的,就一定可以超过一半
然而接下来就没想到了…
这题有一个很奇妙的性质,就是会多出一个
先按a从小到大排序,然后最后一个一定选
剩下的两两一组,每一组选b大的
这样一来,顺着看下来,每一组都是b大的
倒着往前看,显然有每一组都是a大的。。
显然符合题意
codeforces804D
显然对于每一个点,dp出他所在连通块距离他最远的距离d
然后每一个连通块求一次直径D
那么两个点x,y联通后,新的直径就是
m
a
x
(
D
x
,
D
y
,
d
x
+
d
y
+
1
)
max(D_x,D_y,d_x+d_y+1)
max(Dx,Dy,dx+dy+1)
对于每一个块按d排序,每一次暴力扫小连通块的所有点,另外一段二分或者双指针就可以很简单的统计答案
可以发现,如果两个连通块的大小都小于根号,复杂度显然就是根号
否则,大于根号的连通块个数不超过根号个,也就是说每一个大于根号的连通块不会被扫超过根号次
因此复杂度就是根号的,就可以通过了
实现的话,套上一个记忆化就可以了,并不需要讨论是否大于根号
codeforces1492E
想了半天不知道怎么搞,一直去想根号去了…
如果长度比较小,就对于第一个串暴力枚举两位
如果个数比较小,就不会
看题解发现爆搜就可以了
具体来说,还是假定第一个串为起始串,然后尝试进行修改
逐步比较
如果差异<=2不用管
如果差异>4,显然无解
否则,暴力枚举哪些位和当前串看齐,然后从2开始检查爆搜
复杂度的话
复杂度的话,当我们第一次遇到需要看齐的串时
就算改满两个,也就是
C
4
2
=
6
C_4^2=6
C42=6次重新检查
在重新检查过程中,同样的最多6次
这已经是一个非常松的上界了,故复杂度为
6
∗
6
∗
n
m
6*6*nm
6∗6∗nm
想了半天枚举两个串居然没有想到爆搜
codeforces1481D
大力分类讨论
显然如果有一条边正反一样,那么一直走就可以了
否则,如果m是奇数,随便找两个点反复走abababababa即可
否则
如果找三个点x,y,z使得x->y,y->z的颜色一样
没有一定无解
如果m%4=0,yzyxyzyx…地走就可以得到abbaabba…
如果m%4=2,先走一半的xyxyxyxyx,再走yzyzyzyzy,就可以得到ababababab,babababababa
然后就做完了
codeforces1481E
可以发现,除了最后当末尾的一堆可以部分颜色移动,其余的种类都是一起搬的
把每一种抽象为线段,其实就是要线段互不相交
胡乱dp一下就好了
然后暴力枚举最后一段的颜色,可以得到答案
牛客练习赛75D
可以发现,从小到大合并就是最优的
但是数值很大,不能简单用set维护
因为有加法,因此取对数也不好
考虑观察性质
对于原序列最大值p,如果取两个最小值合并后比p大,那么以后就不用排序了
用队列简单维护即可
因为(a,b,c,d,…p),如果
x
=
a
∗
b
+
k
>
=
p
x=a*b+k>=p
x=a∗b+k>=p,则x肯定会背放到末尾,而
c
∗
d
+
k
>
=
a
∗
b
+
k
c*d+k>=a*b+k
c∗d+k>=a∗b+k故下一次一定会被放在末尾,因此之后每一次合并完的数一定在末尾
故之前用堆维护,之后用队列维护即可
uoj495新年的促销
80分的做法也挺有启发性的
一般来说
f
i
,
j
,
k
,
l
f_{i,j,k,l}
fi,j,k,l表示前
i
i
i个,拿了
j
j
j个,白嫖了
k
k
k个,花了
l
l
l元
最用更新答案的时候,其实我们只需要判断最后
k
≤
2
⌊
j
/
a
⌋
k\le 2\lfloor j/a \rfloor
k≤2⌊j/a⌋
不妨把式子改一改
0
≤
2
⌊
j
/
a
⌋
−
k
0\le 2\lfloor j/a \rfloor-k
0≤2⌊j/a⌋−k即
0
≤
j
−
a
⌊
k
/
2
⌋
0\le j-a \lfloor k/2 \rfloor
0≤j−a⌊k/2⌋
因此我们不妨把j,k压为一维,即
j
−
a
⌊
k
/
2
⌋
j-a \lfloor k/2 \rfloor
j−a⌊k/2⌋,维护的时候还要维护k的奇偶性
复杂度为
O
(
n
2
m
)
O(n^2m)
O(n2m)
如果有b的话,用同样的方法不好讨论
不妨先思考一下,如果告诉我们一共拿走哪些,我们要怎么抉择
显然按照钱排序,买便宜的,白嫖贵的
因此得到一个结论,就是一定存在一个断点,使得前面的都是拿的,后面的都是白嫖的
简单DP即可
uoj497新年的复读机
这题显然需要观察一些性质
对于
[
l
,
r
]
[l,r]
[l,r],假设一个决策点
k
k
k,不妨设
g
c
d
(
[
l
,
k
]
)
<
g
c
d
(
[
k
+
1
,
r
]
)
gcd([l,k])<gcd([k+1,r])
gcd([l,k])<gcd([k+1,r])
先合并
[
l
,
k
]
,
[
k
+
1
,
r
]
[l,k],[k+1,r]
[l,k],[k+1,r],再两段合在一起,不如
[
l
,
k
]
[l,k]
[l,k],然后右边一个一个合过来
其实这也等价于
[
l
,
r
]
[l,r]
[l,r]只会从
[
l
,
r
−
1
]
[l,r-1]
[l,r−1]或
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]转移过来
由此,我们可以用归纳法推出,一定存在一个最优方案
使得我们固定一个中心点
i
i
i,然后左右一次合并过来
同时,我们可以发现,左右合并的顺序,在gcd发生改变之前移动不会变
因此,左右各只有log个断点
提出来,大力DP就可以得到一个
O
(
n
l
o
g
2
A
)
O(nlog^2A)
O(nlog2A)的做法
继续分析
断点之间相互配对并非都是有效的
比如
[
i
,
r
]
[i,r]
[i,r],
[
l
,
i
]
[l,i]
[l,i]均发生生了gcd的改变,但是
[
l
,
r
]
[l,r]
[l,r]和
[
l
−
1
,
r
]
[l-1,r]
[l−1,r]没有发生gcd的改变,那么这个状态就是没有用的
这说明,有用的状态一定满足
[
l
,
r
]
[l,r]
[l,r]要么
l
l
l是
r
r
r的gcd变化点,要么
r
r
r是
l
l
l的gcd变化点
发现状态数下降为
O
(
n
l
o
g
A
)
O(nlogA)
O(nlogA)了
转移的话,从一开始得出的
[
l
,
r
−
1
]
[l,r-1]
[l,r−1],
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]转移过来
可以知道如果
r
−
1
r-1
r−1,显然是一直减到第一个有效的区间
[
l
,
k
]
[l,k]
[l,k],然后
[
k
+
1
,
r
]
[k+1,r]
[k+1,r]一个一个并过来
l+1同理,因此我们可以知道每一次询问一个最近的有效区间即可
具体实现的话,先把所有区间预处理出来,然后按长度从小到大排序,依次处理即可