21.11 杂题
mark 一些自己最近见的经典题。每题大概都会有听过不同做法。难度还是按 cf 那篇的难度来判。有一些部分还不是很懂先留坑。
P1[4]
https://www.luogu.com.cn/problem/P2161
这题主要有一车不同的做法。
算法1
考虑直接线段树区间染色,然后如果查询的区间有部分到了这某个区间,就把这个区间删掉。复杂度 \(O(n\log^2{n})\) 吧(大概)。
算法2
分块做法更加暴力,每个块搞一个vector存所有经过这个块的区间即可。复杂度 \(O(n\sqrt{n})\)。
算法3*
考虑树状数组。还不是很懂。
算法4
还有一个平衡树的思路,或者叫区间树。我们定义 \(<\) 为严格在其左边的,\(>\) 同理,那么所有有交的部分就是相等的部分。这个平衡树使用 stl set维护即可。
P2[4]
A 要确定 \(p_i\),B 要确定 \(q_i\),有一个式子 \(\sum a_ip_i(1-q_i)\),A 要最大化这个式子,B 要最小化这个式子。求最后这个式子的值。\(\sum p_i=1,\sum q_i=1\)。\(1\le n\le 30,1\le a_i\le 40\)
根据最小最大值定理,我们发现满足一个人(也就是求min的max)即可满足另一个人。
算法1
二分一个答案 mid。考虑B能否让式子的值 \(\le mid\)。那么只需考虑 \(a_i > mid\) 的 \(i\),然后要满足 \((1-q_i)a_i\le mid\),也就是 \(q_i\ge 1-\frac{mid}{a_i}\)。注意 \(q_i\ge 0\)。然后求和看有没有超过 \(1\) 即可。
算法2
根据二分算法可以得知 \(mid=\frac{n-1}{\sum \frac{1}{a_i}}\) 是临界点。但其实不然,因为老师有可能不去某些教室,然后发现去的教室一定是从大到小排好序的一段前缀(这样可以让分母尽量小)。于是可以 \(O(n+V)\) 做。
算法3
考虑拉格朗日乘数法,可以算出 \(p_i\) 与 \(\frac{1}{a_i}\) 成正比(大概是柯西的条件),然后设比值为 \(k\)。根据 \(\sum p_i=1\) 可以算出 \(k=\frac{1}{\sum \frac{1}{a_i}}\),然后带回原式,发现答案即为 \(\frac{n-1}{\sum \frac{1}{a_i}}\)。剩下的部分同算法2。
P3[4]
https://www.luogu.com.cn/problem/P4643
算法1
这种套路见多了也就觉得不难了。
注意到最后是求两者之差而不是都求出来,那么一定有猫腻。那么考虑每条边的贡献,如果两个端点都在A的集合内贡献是 \(c\),在不同的集合贡献是 \(0\),否则是 \(-c\),那么考虑把这个贡献算到两个点里,分别给两个点加 \(c/2\),容易发现这就对了。然后从大到小排序依次选即可。那么这道题就做完了。
P4[5]
http://noi.ac/contest/596/problem/2530
求 \([x^m]\prod_{i=1}^{n} \sum_{j\ge 0} (a_ij^3+b_ij^2+c_ij+1)x^j\),\(nm\le 10^7\)。
算法1(std)
我们观察一下后面那个生成函数:
然后再类似的推一推可以得到:
于是上面的部分直接卷积,下面相当于卷上一个 \(\sum_{i\ge 0}x^i\) 四次,也就是做四次前缀和。
算法2
记 \(f_n=an^3+bn^2+cn+1\)。然后考虑爆求通项,这玩意显然线性递推,于是高消消消乐。但是这个做法挺没前途的eeee。
算法3*
还是推生成函数。这里简记一些生成函数的性质(选自《具体数学》)。
然后大概知道了这些性质也就可以做题了:
反正也就是用上面的性质,先不管了。
P5[5]
http://www.szoj.net/contest/441/problem/6787
算法1(std)
考虑把最短路图(网)建出来,然后必然是加一段1到n的必经边。然后考虑剩下的边的情况,直接考虑不好考虑,所以二分答案,把所有可行的边(\(dis[1,u]+dis[v,n]+w(u,v)<mid\))加入,再判断修改必经边是否可行即可。
算法2
上述算法不好直接考虑的原因是这是一个图,我们考虑建出最短路树。然后考虑一个经典结论:
- 如果段一条边,其他非树边产生的贡献(其中一点为 \(n\) 的子树内的点) \(dep_u+dep_v-dep_n+w(u,v)\) 或者 \(dep_u-dep_v+dep_n+w(u,v)\) (\(v\) 是 \(n\) 的祖先),且最多经过一条非树边。
然后对于删除 \(n\) 的祖先这条链的边都可以产生贡献,于是就变成了一个区间取 \(max\),只有单点查询直接标记永久花即可。
算法3
好像对于所有这样的边从小到大排序,然后树上并查集合并一条链代表段这一条链的最小值都是当前值。
算法4
算法2的过程还可以直接线段树合并。
P6[8]
http://www.szoj.net/contest/441/problem/6468
转换问题把边看成两个不同的点,然后在同一顶点处匹配两条”边“。于是这等价于 \(K_{2,2,2,...}\) 匹配。
算法0
打表&oeis
算法1
根据 U 群大佬,先容斥得到和式,然后写成卷积形式列生成函数,然后 ODE(成熟方法)
可以得到和 oeis 同样的递推式
算法2*
考虑dp,记 \(f_{i,0/1/2}\) 代表前 \(i\) 组还有 \(0/1/2\) 个点没有匹配的方案数。然后转移。
具体还不是很懂,先留个坑(
P7[6]
https://www.luogu.com.cn/problem/P6822
P8[7]
https://www.luogu.com.cn/problem/CF156D
算法1
直接背结论:\(n^{k-2}\prod a_i\)。
P9[5]
https://www.luogu.com.cn/problem/CF1149C
线段树 Merge 的经典套路。考虑所有为 \(s[k+1,r]-s[l,k]\),那么就枚举 \(k\) 在 \(mid\) 的哪边。
P10[3]
https://www.luogu.com.cn/problem/P4145
Segment beat 裸题。我们发现如果一个点不会被改多次的话就暴力去改,复杂度 \(O(n\log n\log\log n)\)。
P11[5]
https://www.luogu.com.cn/problem/P7888
子序列相关计数的经典题。要求本质不同,那么考虑一个套路:在其第一次出现的地方计数。
那么考虑一个子序列 \(p_1,p_2,...,p_k\),其对应颜色为 \(c[p_1],c[p_2],...,c[p_k]\),那么所有包含其的子序列就得满足条件:
- \([1,p_1-1]\) 中不能有 \(c[p_1]\) 这种颜色
- \([p_1+1,p_2]\) 中不能有 \(c[p_2]\) 这种颜色
- \(\dots\)
- \([p_k+1,n]\) 中随便选。
那么我们对于一种答案就可以对包含其的子序列计数。但是这样还不是多项式式复杂度
考虑子序列相关的一种dp套路,记 \(f_i\) 代表以第 \(i\) 个数结尾的答案,也就是 \(i=p_k\),那么枚举上一个是啥,设为 \(j\)。有 \(f_i=f_j\cdot 2^{w(j,i,s_i)}\),其中 \(w(i,j,c)\) 代表 \((i,j)\) 中有多少个不是 \(c\) 的元素。复杂度 \(O(n^2)\)。然后考虑优化,这个形式看上去很前缀和,我们只需要维护前缀 \(\times 2\) 即可。但是我们发现这个 \(\times 2\) 和具体的 \(s_i\) 有关,大概可以对面的每个位置 \(j\),维护 \(g_{j,c}=f_j\cdot 2^{w(j,i,c)}\),然后考虑维护这个东西的前缀和,于是对每种颜色维护好像就可以了,复杂度 \(O(\mid\sum\mid n)\) 可以通过。
P12[8]
http://www.szoj.net/contest/429/problem/6453
直接记录 \(lst_i\) 为在其之后最近的同色点出现位置减去它的位置的值。然后判断这个值是否相同即可。然后我们发现是要求后缀的 \(lcp\)。然后发现可以后缀排序比较,直接比较用可持久化平衡树多一个 \(log\),我们可以使用可持久化分块平衡复杂度。
P13[7]
http://www.szoj.net/contest/427/problem/6440
直接树形背包,然后发现转移大概是:
于是你发现这就是一个(最多)\(n\) 次多项式。于是考虑插值的套路直接维护点值的上述式子的和。然后这个就很好换根,然后就可以 \(O(n^2)\) 了。
P14[6]
https://www.luogu.com.cn/problem/CF981E
考虑线段树分治,然后bitset优化背包dp即可。