2019集训队作业做题实况[3](61-66):

24-2(计数)(19.12.29):

https://atcoder.jp/contests/agc035/tasks/agc035_f

https://atcoder.jp/contests/agc035/submissions/9203617

对于行i和列j,只有k[i]=j,l[j]=i-1,或k[i]=j-1,l[j]=i会重复。

所以容斥枚举一共有多少对行列是这样重复的即可:

(Ans=sum_{k=0}^{min(n,m)}C_n^k*C_m^k*k!*(n+1)^{m-k}*(m+1)^{n-k}*(-1)^k)

42-1(匹配+构造)(20.2.1):

https://codeforces.com/contest/547/problem/D

https://codeforces.com/contest/547/submission/69965423

方法1:

首先这是一个二分图,原来的点就是二分图上的边。

如果所有点的度数都是偶数,可以跑若干次欧拉回路。

回路上的边交替染色即可。

一个点是奇数的话,就随便断它的一条边。

之后接回去的时候看看颜色即可,这样显然差不超过1.

方法2:
点还是点。

对于x相同的,若有k个,则连k/2条边,边连接的点互不相同,k奇数的话剩下一个不用管。

y相同的同理。

这样染色,使每条边的两个点的颜色不同即可。

可以证明不会有冲突(奇环),因为走的边一定是x轴和y轴的边交替走,想要回来一定要走偶数条边。

45-1(计数+树形dp)(20.2.6):

https://codeforces.com/contest/512/problem/D

https://codeforces.com/contest/512/submission/70426270

先考虑哪些点是不合法的:
1.边双里的点

2.边双之间的路径上的点

找到这些点可以通过直接Turpo找。

那么剩下的点显然是个森林,我们把树分成两种:
1.有根树,即这棵树有一个点和不合法的点有连边(不可能有两个这样的点),那么这个点一定是这个树最晚取走的点,以它做根,对于每个子树同样满足这个性质,所以树形dp设(f[i][j])表示i为根的子树里选了j个点的方案数。

转移显然,主要i一定是最后一个点,所以(f[i][siz[i]]=f[i][siz[i]-1])

2.无根树, 就是没有那样的点的树。这个枚举每一个点做根,做那样的dp,把所有结果加起来,注意对每一个大小为x的子树,会被不属于这个子树的点作根时统计到一遍,所以除以(siz-x),当x=siz时不用除以。

复杂度由树形背包可得是(O(n^3))

39-1(推理讨论+ecgcd+最短路)(20.2.6)

https://codeforces.com/contest/516/problem/E

https://codeforces.com/contest/516/submission/46652574

杂题分享时淘过的,随便丢一篇题解:
https://blog.csdn.net/jokerwyt/article/details/103021688

12-3(动态规划+NTT)(20.2.7):

https://atcoder.jp/contests/agc021/tasks/agc021_f

https://atcoder.jp/contests/agc021/submissions/9937374

(f[i][j])表示i行j列,其中i行一定不为空的方案数。

考虑新加一列,有k行在前j列的没有染色,在新加的这列有了染色。

当k=0时,只用考虑原来的j行对这一列的最小最大行影响:

(f[i][j+1]+=f[i][j]*(1+i+C(i,2)))

否则,考虑把k行插入原来的j行中,但是新的列的最大最小行还可能是原来的j行,分2*2=4种情况(即上下是否是原来的)可以得到系数

(f[i+k][j]+=f[i][j]*((C(i+k,k)+C(i+k,k+1)+C(i+k,k+1)+C(i+k,k+2))=C(i+k+2,k+2)))

最后(ans=sum_{i=0}^nC_{n}^i*f[i][m])

第二个转移可以NTT优化,时间复杂度:(O(nm~log~n))

19-2(动态规划+xjb优化)(20.2.17):

https://codeforces.com/contest/708/problem/E

https://codeforces.com/contest/708/submission/71224703

考虑一行一行的转移,设(f[i][l][r])表示前i行联通,第i行剩[l,r]的概率和。

(f[i][l][r]=p[l][r]sum_{[u,v]∩[l,r]≠∅}f[i-1][u][v])

(p[l][r])表示一行k轮后剩([l,r])的概率。

(v[i])表示一行的左边搞了i个概率,

(v[i]=p^i*(1-p)^{k-i}*C_{k}^i)

(p[l][r]=v[l-1]*v[m-r])

直接做(O(n^5)),显然可以前缀和优化。

(s)(f[i-1])的二维前缀和,那么:
(f[i][l][r]=p[l][r]*(s[m][m]-s[l-1][l-1]-s[m-r][m-r]))

(-s[m-r][m-r])是因为对称性。

发现用到的都是(s[x][x])这样的。

干脆直接维护(s[x][x])吧。

(g[i][j]=sum_{x<=j}sum_{y<=j}f[i][x][y])

(g[i][j]=g[i][j-1]+sum_{x<=j}f[i][x][j])

(g[i][j]=g[i][j-1]+sum_{x<=j}p[x][j]*(s[m][m]-s[x-1][x-1]-s[m-j][m-j]))

(g[i][j]=g[i][j-1]+sum_{x<=j}v[x-1]*v[m-j]*(s[m][m]-s[x-1][x-1]-s[m-j][m-j]))

从小到大枚举j维护两个东西的和就可以了。