Loading

模拟57—「2A·2B·2C·2D」

2A

纯模拟

2B

大家都当水题做,我做了一个半小时,生草,太菜了。

一开始根据题目先推了一个性质,一段区间删完之后,剩下的只能是 \(A\) ,特殊情况有 \(P\) , 当且仅当 \(P\) 是第一位。
然后就可以写一个区间 \(dp\) , \(f_{l,r,0/1}\) 代表区间 \([l,r]\) ,最左边是否有 \(P\) 下的最小剩余字母,转移显然。

然而时空双爆,考虑换做法, \(f_{i}\) 代表 \([1,i]\) 的最小剩余字母。
如果这一位是 \(A\) , 那么肯定要加一,因为 \(A\) 前面接啥都删不掉。
如果这一位是 \(P\) , \(P\) 前面接啥都能删掉,所以如果 \(f_{i-1}>0\) 就减一,否则加一。

然后发现转移只和 \(f_{i-1}\) 有关,所以把它唯一的一维滚掉就好了。

for( R i = 1 ; i <= n ; i ++ )
    if( s [i] == 'A' ) now ++ ;
    else ( now ) ? now -- : now ++ ;
printf( "%d\n" , now ) ;

2C

数据太水,别说 \(n^4\) , \(\frac{n^5}{32}\) 都能过。
正解还是有点 nb 的。

首先可以推出来性质就是如果一个点的祖先们里面有祖先关系,那么只需要考虑最年轻的祖先。
集合角度理解是全包含,画个图也能理解。

所以就可以在每个点把所有祖先按出现时间排序。
如果一个点已经被加入,说明他是这个点祖先的祖先,直接忽略。
否则检查这个点的集合和已经有的集合是否有交,有交说明不合法,因为他们既没有祖先关系,还有公共祖先。

bitset 复杂度中的 \(any,none,==0\) 都是 \(n/32\) 的,所以还是乖乖写正解吧

2D

数据太水,直接从小到大删可以过(但是我不会卡)。
正解还是很 nb 的。

先求出来每个点最多能在几度子图里面出现。

这个沈队有一个 \(nb\) 的方法,用 \(vector\) 类拓扑排序求出来。
思考他的性质,一个点最后出现的 \(k\) 度子图的 \(k\) 一定小于等于他自己的度数。
并且这个 \(k\) 会取等,当且进当他连的所有边的点度数都大于等于他。
每连一个度数小于他自己度数的点,这个点就不能算进他最终答案的 \(k\) 中,所以他的 \(k\) 会减小一。

以上过程用 \(vector\) 可以实现,具体就是每个度数开一个 \(vector\) , 从小到大扫,度数变化就重新加进去,只有第一次扫统计答案。
初始有 \(n\) 个点,度数变化 \(m\) 次,固复杂度为 \(O(n+m)\)

注意 auto 不能找到新 push_back进去的元素,所以要用 j<v.size()

然后从大到小考虑扩展当前集合。
先把一个点连的其他集合合并起来(n,m,b全部相加),考虑加入这个点会对集合造成什么贡献。

首先n的额外贡献就是+1,m的额外贡献就是跟它相连的点中大于等于他的(等于要特判防止重复)
b的额外贡献有点意思,先加入所有比他小的点的贡献。
但如果只计算这个,会导致计算重复,所以加入这个点的时候,所有比他大的点都计算过他,所以要去掉。

放一个 阿克曼 复杂度的并查集的板子,就是让小的合并到大的上面=。

inline int fd( int x ){ return ( x == F [x].fa ) ? ( x ) : ( F [x].fa = fd( F [x].fa ) ) ; }
inline void un( int x , int y ){
    x = fd( x ) , y = fd( y ) ;
    if( x == y ) return ;
    if( F [x].dep > F [y].dep ) swap( x , y ) ;
    F [x].fa = y ;
}

总结

这场T2脑子抽了想了半天,T3暴力就能水过去,失策了。
这场难度不对,所以没什么可总结的。

posted @ 2021-09-20 21:31  Soresen  阅读(110)  评论(1)    收藏  举报