AGC038D
(mathtt{color{red}{T},color{green}{W}})
首先如果 (a,b) 只有一条路径,且 (b,c) 只有一条路径,那么 (a,c) 一定只有一条路径。显而易见的,(a,c) 之间的合法路径只能为 (a ightarrow b ightarrow c) 。因此将所有的由 (0) 类边连起来的点放在一起,形成一个联通块(显然只能是一棵树)。
假设有 (k) 个联通块,因为每个联通块都是一棵树,因此还剩下 (m-n+k) 条边。
如果这个时候没有 (1) 类边的话:
- 边数的最小取值:将 (k) 棵树连起来的边数花费为 (k-1) 。
- 边数的最大取值:比较显然的是因为同一联通块中的点不能属于一个环内,所以钦定每个联通块有一个"外交官"专门负责向外面连边,其他点都不能向外面连边。这样的话 (k) 个"外交官"可以随便连边,因此边数为 (frac{k(k-1)}{2}) 。
如果有 (1) 类边:
- 如果只有两个联通块:想不出怎么构造了,无解。
- 如果有一条 (1) 类边的两个端点属于同一联通块:两个同一联通块的点不能放在一个环里面,无解。
- 边数的最小取值:将 (k) 个"外交官"连成一个环即可,边数为 (k) 。
- 边数的最大取值:同样是 (frac{k(k-1)}{2}) 。
维护一下联通块,然后判断 (m) 是否在合法区间内即可。
ARC070D
(mathtt{color{red}{T},color{green}{W}})
当 (bgeq a) 的时候,不友好的人完全可以用一个大小为 (a) 的子集模仿诚实的人,这样无论如何都无法得到解。
考虑先找出一个诚实的人,然后用这个诚实的人依次检查所有的人。如何找这个诚实的人呢?
考虑到询问一对 x y
,如果答案为 NO
的话,意味着这两个人之间至少有一个不友好的人。这个时候将这两个人直接删掉仍然满足 (a>b) 。如果答案为 YES
,两人的身份有三种情况,不好判断,但是容易发现,将所有的 NO
二元组删掉后,剩下的所有人一定满足前一段是不友好的,后一段是诚实的,而且至少存在一个诚实的,因此遇到 YES
什么都不干就好了,最后剩下的这个序列取最后一个人即可,这个人必然是诚实的。
用栈维护整个操作即可。
不瞄题解做不出来 atcoder,难受 >_<
「HEOI2016/TJOI2016」排序
(mathtt{color{green}{T},color{green}{W}})
二分最终的答案,然后就可以将原序列变成 01
序列。
然后两个操作都变成了区间推平操作了,线段树维护即可。
「国家集训队」middle
(mathtt{color{red}{T},color{green}{W}})
主席树神题。
中位数的一个套路:转化成 01
序列。
问题就在于二分一个 (mid) 后,对于这个 01
序列,怎么求一个区间的前缀最大值和后缀最大值。
不妨考虑每一个 (mid) 都建一颗线段树维护对应 01
序列以及前缀最大值后缀最大值区间和等,不过空间开不下。但可以发现如果将 (mid+1) 的话只有一个位置发生了改变,因此可以将线段树替换为主席树维护。
「TJOI2015」棋盘
(mathtt{color{green}{T},color{red}{W}})
显然需要在意的只有第 (i) 行前两行的棋子状态。
这样列出 (dp) 后矩阵快速幂优化即可。
「SDOI2017」序列计数
(mathtt{color{green}{T},color{red}{W}})
考虑用所有方案数减去不合法方案数。
考虑不合法方案数怎么求,将所有合数按照 (pmod{p}) 的结果分类,就可以得到 (g(i)) 表示选择一个模 (p) 后等于 (i) 的数的方案数。因为 (p) 很小,这样就可以直接矩阵快速幂了。
所有方案数一样也是直接矩阵快速幂好了。
ARC058E
(mathtt{color{red}{T},color{green}{W}})
(5+7+5=17) 十分小,考虑状压。
比方说 (4,2) 压成 (010001),(1,5) 压成 (100001) ,只压 (17) 位。第 (k) 位上有一相当于 (i) 有一段后缀的和为 (k),因此合法当且仅当 (x+y+z,y+z,z) 位上都有 (1) 。
令 (dp(i,j)) 表示前 (i) 个数不合法的方案数,且当前状态为 (j) 。转移的时候考虑下一个数选什么,得到目标状态后检查是否同时包含 (x+y+z,y+z,z) 三个位置即可。
最后的答案显然是 (10^n-sum dp(n,i)) 。
int lim=(1<<(x+y+z))-1;
int res=(1<<(x+y+z-1))|(1<<(y+z-1))|(1<<(z-1));
dp[0][0]=1;
lep(i,1,n) lep(S,0,lim) lep(k,1,10) {
int T=((S<<k)|(1<<(k-1)))&lim;
if((T&res)!=res) pls(dp[i][T],dp[i-1][S]);
}