Day 1
P1373 小 a 和 uim 之大逃离
话说相同不应该都死吗?
看到 n,m,k 都小的一匹,考虑全部枚举了。
定义状态:
dpi,j,d,p
表示这一步走到了 i,j,差值为 d,最后一步是由 p 走的。
方程过于板子了:
dp[i][j][d][0]=dp[i][j][d][0]+dp[i-1][j][(d-a[i][j]+k)%k][1];
dp[i][j][d][0]=dp[i][j][d][0]+dp[i][j-1][(d-a[i][j]+k)%k][1];
dp[i][j][d][1]=dp[i][j][d][1]+dp[i-1][j][(d+a[i][j])%k][0];
dp[i][j][d][1]=dp[i][j][d][1]+dp[i][j-1][(d+a[i][j])%k][0];
——k 记得加 1。
CF31E Funny Game
由于太像C的TJ了,所以我讲详细一点(以证明我不是C的)。
首先这是道博弈论对吧(要是这都看不出来就。。)
考虑一下,当先手拿和不拿 i+1 号石头的情况。
如果不拿,等于正在处理 i 号石头,因为如果 i+1 都不拿,i+k(k>1) 都不会拿。则有 dpi=dpi+1
如果拿,那么这一步获得的 s 为 j=1∑i+1aj,而后手获得 dpi+1,相当于获得的差值为 ∑aj−dpi+1。
所以 dpi=maxdpi+1,∑aj−dpi+1。
由于 dpn 无意义,从 dpn−1=an 开始即可。
答案:dp1。
CF1006F Xor-Paths
双向广搜,一眼就会。
由于向下走 n 步,向右走 m 步,每次可以选走向下和向右,总的时间复杂度高达 O(2n+m),直接挂掉!
考虑一下双向搜索,从顶点和终点往对角线的方向搜即可。
Day 2 考试
T1
简述题意:(i,j)→(i+1,j) 有一条 ai+bj 的边;(i,j)→(i,j+1) 有一条 ci+dj 的边。ai,bi,ci,di 单调不降。问图的最小生成树。
因为单调不降,所以答案只会从左边和上面两条边转移过来。答案等于 ∑minai+bj,ci+dj。
定义 Ai=ci−ai,Bi=di−bi,这一坨答案为 ai+bj+min{0,Ai+Bj},把 ai+bj 提出了,对 min{0,Ai+Bj} 排序即可。
T2
简述题意:求两个字符串的编辑距离,如果大于 50,输出 −1。
编辑距离的 DP 公式原因,在此处不再赘述。定义 dpi,j 表示 a 的前 i 个字符和 b 的前 j 个字符的编辑距离。
dpi,j=⎩⎨⎧maxi,jmin{dpi,j−1,dpi−1,j,dpi−1,j−1}+1dpi−1,j−1mini,j=0ai=bjai=bj
对于距离超过 50 的字符串,进行 dp 是没有意义的。所以用 fi,c 记录 dpi,j+c−50 即可。
T4
我自己的题解
Day 3
P2279 [HNOI2003] 消防局的设立
贪心题。
如果一个点没有收到消防站的覆盖,那么就在它的祖先处设立一个消防站。从深度最低的往最高的扫即可。
为什么这是最优的?在父亲节点处不是还能照顾到自己的兄弟吗?注意:这个点是目前深度最低的无法覆盖的点,如果祖父盖不到,说明这个点深度一定不是最低的。
每建立一个消防局,扫描两层即可。看起来这是 O(n3) 的,实际上每条边最多被扫到 n 次,时间复杂度不超过 O(n2)。
注意将 a 的父亲设为它自己,这样所有点的祖先不超过 1。
for(int i=2;i<=n;i++)
{
cin>>a[i].fa;
a[i].gf=a[a[i].fa].fa;
a[i].dep=a[a[i].fa].dep+1;
a[i].i=i;
G[i].push_back(a[i].fa);
G[a[i].fa].push_back(i);
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) dy[a[i].i]=i;
for(int i=1;i<=n;i++)
{
if(x1[i]||x2[i]) continue;
x1[dy[a[i].gf]]=1;ans++;
dfs(a[i].gf,2);
}
CF893E Counting Arrays
一道很好的计数题喵。
先考虑正负数的问题。因为 1≤x≤106,所以这些数字乘起来一定是一个正数,所以我们先乱填前 y−1 个数的正负,最后一个在改回来就可以了。所以正负数的可能方案数为 2y−1。
这个题一看就要质因数分解。定义:
x=i=1∏kp1e1p2e2⋯pkek
其中 p1,p2,⋯pk 是两两不等的质数。
对于每一个指数 ei,它们会被分到这 y 个数上去。由于这是一个序列,所以这 y 个数本质不同。但是这 ei 个 pi 本质相同,并且可空。这时就变成了大型记录片之《小球进盒子·第三集》。
| 球 |
盒子 |
可空? |
方案数 |
| 相同 |
不同 |
可 |
(m−1n+m−1) |
——by sLMxf
所以对于每一个指数 ei,它的方案数为 (y−1y+ei−1)。
所以最终的答案为:
2y−1i=1∏k(y−1y+ei−1)
分解质因数是 O(x),快速幂是 O(logy) 的,组合数预处理 O(maxy),单次查询 O(1)。
故总的时间复杂度为 O(maxy+qx)。
Day 4
CF360B Levko and Array
我自己的题解
P9751 旅游巴士
最短路。
首先这题的 二分套分层图 BFS 一眼就可以看出来对吧。
然而交上去荣获 100WA。为什么?因为要建一张反图。
Buy Low Sell High
本题和 CF1974G 很像。
事实证明,像到是一点也不像,但都是反悔贪心。
考虑一种贪心:每次只要能够赚取利益,就从 q 中拿一个最小的出来,否则把这个东西放进 q。
然而会有这样一种 hack:
3
1 2 114514
显然这个时候拿一个 114514−1=114513 是最优解,但程序会输出 1。为什么?因为 2 把 1 抵掉了。
考虑这样一件事:每一次用从之前拿过的最优解,把最大的替换掉。先考虑拿新的,在考虑拿旧的。
典型反悔贪心。时间复杂度是优先队列的 O(nlogn)。代码如下:
for(int i=1;i<=n;i++)
{
cin>>m;
if(!q.empty()&&q.top()<m)
{
ans+=m-q.top();
q.pop();
q.push(m);
}
q.push(m);
}
附:大型纪录片之《小球进盒子·全篇》
| 球 (n) |
盒 (m) |
可空? |
答案 |
| 相同 |
相同 |
可 |
partition(n+m,m) |
| 相同 |
相同 |
否 |
partition(n,m) |
| 相同 |
不同 |
可 |
(m−1n+m−1) |
| 相同 |
不同 |
否 |
(m−1n−1) |
| 不同 |
相同 |
可 |
i=1∑nS(n,i)=i=1∑n{in} |
| 不同 |
相同 |
否 |
S(n,m)={mn} |
| 不同 |
不同 |
可 |
mn |
| 不同 |
不同 |
否 |
m!S(n,m)=m!{mn} |
- partition(n,m) 表示把 n 个相同的球放到 m 个相同的盒子的方案数/把数字 n 分成 m 个部分的方案数。计算方法:
f(n,k)=f(n−1,k−1)+f(n−k,k)
- S(n,m) 是斯特林数。