我是靠谱客的博主 想人陪绿茶,最近开发中收集的这篇文章主要介绍Codeforces Round #791 (Div. 2) 部分题解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

A AvtoBus

不难发现如果我们要车尽可能多,那么我们就需要最大化 4 4 4 的数目,尽可能少的情况就是最大化 6 6 6 的数目,我们同时发现 2 2 2 6 6 6 轮车等价于 3 3 3 4 4 4 轮车,有了这两个性质就不难解决。

B Stone Age Problem

考虑两种修改对于答案的影响,由于我们只关注序列权值的总和,我们只要记录什么时候进行了修改,在单点修改时判断下即可。

C Rooks Defenders

不难发现如果要将一个矩阵填满,那么有且仅有所有行均被覆盖或者所有列均被覆盖才合法,所以我们对于行和列分别维护线段树,以行举例,当一行上棋子数目不为零时就 + 1 +1 +1 ,为零时就 − 1 -1 1即可。

D Toss a Coin to Your Graph…

首先如果要让最大值最小,我们可以考虑二分这个最大值 M M M,这样我们对于一个图 G G G 就有了一些权值大于 M M M 的点是不能进行选择的,我们将这些点从图中删去得到一个子图 S S S,这个图上是可以随便走的。问题就转化成了在图 S S S 上去找一条包含点数为 k k k 的路径。
首先如果图 S S S 中有环,那么就一定合法,判环的代码如下:

void findcur(int x){
    col[x]=1;
    for(auto v:e[x]){
        if(!tag[v]) continue;//tag[v]=false当且仅当val[v]>M
        if(col[v]==1){
            flag=true;
            break;
        }
        else if(col[v]==-1) continue;
        else findcur(v);
    }
    col[x]=-1;//表示以x为起点的路径上没有环
}

如果没有环我们就记忆化搜索下最长路径与 k k k 比较即可。

E Typical Party in Dorm

我们首先考虑一个左端点为 l l l,右端点为 r r r 的子串对于答案的贡献:
我们将该字串分为若干点对,其中 l l l r r r 配对, l + 1 l+1 l+1 r − 1 r-1 r1 配对,依次类推。
我们令 S q S_q Sq 表示某次询问给出的字符集。
这样我们考虑其中的一对 a a a b b b
s [ a ] = ? s[a]=? s[a]=? 并且 s [ b ] = ? s[b]=? s[b]=? 时,我们可以任取给出集合中的字符。
s [ a ] = ? s[a]=? s[a]=? 并且 s [ b ] = t ( t ∈ S q ) s[b]=t (tin S_q) s[b]=t(tSq) 时,那么只有一种合法情况,会产生一个限制条件:集合 S q S_q Sq 中必须含有字符 t t t,反过来同理。
当二者都不为问号时,如果相等则没有影响,如果不等则子串 ( l , r ) (l,r) (l,r) 对答案将不产生贡献。
我们考虑子串以外的字符,不难发现每一个 ? ? ? 都将对于答案产生 ∣ S q ∣ |S_q| Sq 的贡献。
这样我们定义 f f f 为内部产生的方案数, d d d 为外部产生的方案数,对于每个串我们可以确定一个三元组 ( f , d , s t a t e ) (f,d,state) (f,d,state) ,其中 s t a t e state state 为一个二进制数,其第 i i i 位为 1 1 1 表示字符 ′ a ′ + i 'a'+i a+i 是否必须包含于询问集合。
这样我们定义 c [ k ] [ s t a t e ] c[k][state] c[k][state] 表示当限制条件构成的集合大小为 k k k 时,其二进制表示为 s t a t e state state 时的方案数,这个我们可以枚举 l , r , k l,r,k l,r,k 来进行计算。
这样我们考虑我们对于一个询问,其字符集为 Q Q Q,方案数就是:
∑ i ∈ Q c [ b i t c o u n t ( i ) ] [ i ] sum_{iin Q} c[bitcount(i)][i] iQc[bitcount(i)][i]
这个我们枚举子集可以 3 α 3^alpha 3α 进行计算,不过并不能通过本题。
题解给出了一种做法:
我们定义 S ( c u r , i ) = { x ∣ x ∈ c u r 并 且 x ⊕ c u r ≤ 2 i } S(cur,i)={ x| xin cur 并且 x oplus cur leq 2^i } S(cur,i)={xxcurxcur2i}
也就是 x x x c u r cur cur 只有 0 0 0 i i i 位可以不同,并且 x x x c u r cur cur 的子集。
我们有以下转移:
c u r cur cur 的第 i i i 位为 0 0 0 的时候, S ( c u r , i ) = S ( c u r , i − 1 ) S(cur,i)=S(cur,i-1) S(cur,i)=S(cur,i1)
c u r cur cur 的第 i i i 位为 1 1 1 的时候, S ( c u r , i ) = S ( c u r , i − 1 ) ∪ S ( c u r ⊕ 2 i , i − 1 ) S(cur,i)=S(cur,i-1) cup S(cur oplus 2^i,i-1) S(cur,i)=S(cur,i1)S(cur2i,i1)
这样就大大的提升了枚举的效率,将复杂度降到了 α 2 α alpha2^alpha α2α
代码如下:

for(int k=1;k<M;++k){
        for(int i=0;i<M;++i){
            for(int cur=(1<<M)-1;cur>=0;--cur){
                if(cur&(1<<i)) (F[k][cur]+=F[k][cur^(1<<i)])%=MOD;
            }
        }
    }

预处理后对于每个询问的答案就是 F [ ∣ Q ∣ ] [ s t a t e Q ] F[|Q|][state_Q] F[Q][stateQ],复杂度为 O ( α 2 2 α + α n 2 ) O(alpha^22^alpha+alpha n^2) O(α22α+αn2)

最后

以上就是想人陪绿茶为你收集整理的Codeforces Round #791 (Div. 2) 部分题解的全部内容,希望文章能够帮你解决Codeforces Round #791 (Div. 2) 部分题解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(88)

评论列表共有 0 条评论

立即
投稿
返回
顶部