概述
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
r−1 配对,依次类推。
我们令
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(t∈Sq) 时,那么只有一种合法情况,会产生一个限制条件:集合
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]
i∈Q∑c[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)={x∣x∈cur并且x⊕cur≤2i}
也就是
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,i−1)
当
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,i−1)∪S(cur⊕2i,i−1)
这样就大大的提升了枚举的效率,将复杂度降到了
α
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) 部分题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复