uoj76 题解
详细揭秘智力障碍如何通过这个题。
考虑固定一个黑点集合 \(X\) 时如何统计答案:设 \(u\) 的出边集合为 \(out(u)\),在当前时刻(经过前面的时刻都是没有结束的)持有若干 \((S_i,T_i)\) 表示集合 \(S_i\) 中有至少 \(T_i\) 个黑点,初始即为仅一个 \((U,1)\)。考虑对于点 \(u\) 以及一对 \((S,T)\),如果 \(u\not\in S\) 则无效,否则设 \(s=out_u\cap S\),若 \(|X\cap s|+|S_i|-1-|s|<T_i\) 则 \(u\) 必可推出自己为黑点,结束;否则这个时刻后所有人可知 \((s,|T_i|-(|S|-u-|s|))\)。
分析一下,所有时刻的 \(T\) 都是 \(1\)。转化为如果 \(S\not\subseteq out_u\cup\{u\}\) 或 \(u\not\in S\) 则该信息无效;设 \(s=out_u\cap S\),若 \(X\cap s=\varnothing\) 则 \(u\) 可知自己为黑点,否则往信息集合中加入 \(s\)。对每个 \(X\) 模拟该过程是 \(O(4^npoly(n))\) 的。
发现这本质上是一个 bfs 的过程:每个集合 \(S\) 对于一些 \(u\) 存在向 \(S\to S-\{u\}\) 的出边,要求为 \(S-\{u\}\subseteq out_u\),最终要从全集走到与 \(X\) 无交的目标集合,\(u\) 相当于固定最后一条边。每个 \(u\) 的决策是独立的,处理每个 \(S\) 走出边后到达全集的最短路,全体合并起来即可。按照数值大小递推 \(S\) 的时间,再 FMT 合并出子集 \(\min\),复杂度 \(O(2^nn^2)\)。
本质上,就是初始选某个 \(S\cap X=\varnothing\) 作为初态并且在反图首步走 \(u\) 的出边,最终要抵达 \(U\),求出最短路。操作形式不是很好,考虑全体取反,设 \(G_u\) 为 \(out_u\) 的补集,\(S\) 变化过程即为:选 \(u\in S\) 且 \(G_u\subseteq S\),将 \(u\) 从 \(S\) 删除,最终要求 \(S=\varnothing\)。考虑如何避免最开始“选取某个 \(X'\) 作为超集”的步骤,发现这一步可以融合入游走过程:初始令 \(S=X\),每次选 \(u\in S\),执行 \(S\to S-\{u\}\cup G_u\)(注意这里不会先拓展一个 \(v\) 再删掉,这是不优的),求到 \(S=\varnothing\) 的最短路。
那么当前在集合 \(S\) 中的 \(u\) 一定要全部操作一遍,这就比较显然,对于所有 \(v\in G_u\) 建边 \(u\to v\),要求 \(X\) 所有点不能走到环上,否则直接无限。天数就是 \(X\) 可达点集的并,可行的第一步就是 \(X\) 中不可被其他点到达的点的个数。
将可被环到达的点删掉之后是个 DAG,bitset 求可达点集信息并拆贡献算答案,总复杂度 \(O(\frac{n^3}{w})\)。
\(O(4^npoly(n))\) 代码
void solve(){
cin>>n;
F(i,0,n-1){
string str;cin>>str;
F(j,0,n-1)a[i][j]=(str[j]=='1');
}
int ans1=0,ans2=0;
const int mx=(1<<n)-1;
F(i,0,n-1)F(j,0,n-1)if(a[i][j])out[i]^=(1<<j);
F(B,1,(1<<n)-1){
static map<int,int>f;f.clear();
f[mx]=1;
F(_,1,n){
int cnt=0;
vector<int>vec;
F(u,0,n-1){
bool fl=0;
for(auto it:f){
const int s=it.fi;
if((s>>u)&1){
const int t=s&out[u];
if(!(B&t)&&!(s^t^(1<<u))){
fl=1;
break;
} else if(!(s^t^(1<<u)))vec.push_back(t);
}
}
if(fl)++cnt;
}
if(cnt){
ans1+=_;
ans2+=cnt;
break;
}
for(int&x:vec)f[x]=1;
}
}
cout<<ans1<<' '<<ans2<<'\n';
}
\(O(2^nn^2)\) 代码
void solve(){
cin>>n;
F(i,0,n-1){
string str;cin>>str;
F(j,0,n-1)a[i][j]=(str[j]=='1');
}
int ans1=0,ans2=0;
const int mx=(1<<n)-1;
F(i,0,n-1)F(j,0,n-1)if(a[i][j])out[i]^=(1<<j);
F[mx]=0;
dF(s,mx-1,0){
F[s]=inf;
F(u,0,n-1)if((s&out[u])==s&&!((s>>u)&1))chkmin(F[s],F[s^(1<<u)]+1);
}
F(i,0,n-1){
F(t,0,mx)G[i][t]=((t&out[i])==t&&!((t>>i)&1))?F[t^(1<<i)]+1:inf;
F(j,0,n-1)F(s,0,mx)if((s>>j)&1)chkmin(G[i][s],G[i][s^(1<<j)]);
}
F(B,0,mx-1){
int mn=inf,cnt=0;
F(i,0,n-1){
int val=G[i][B];
if(val<mn)mn=val,cnt=1;
else if(mn==val)++cnt;
}
if(mn<=n+1)ans1+=mn,ans2+=cnt;
}
cout<<ans1<<' '<<ans2<<'\n';
}
正解代码
void solve(){
cin>>n;
F(i,0,n-1){
string str;cin>>str;
F(j,0,n-1)a[i][j]=(str[j]=='1');
}
F(i,0,n-1)a[i][i]=1;
int ans1=0,ans2=0;
F(i,0,n-1)F(j,0,n-1)if(!a[i][j])++deg[i];
F(i,0,n-1)if(!deg[i])q[++qR]=i;
while(qL<=qR){
const int u=q[qL++];
vis[u]=1;
F(v,0,n-1)if(!a[v][u]&&!--deg[v])q[++qR]=v;
}
F(i,0,n-1)if(vis[i])f[i].set(i);
dF(_,qR,1){
const int u=q[_];
F(v,0,n-1)if(!a[u][v]&&vis[v])f[v]|=f[u];
}
const int m=qR;
F(u,0,n-1)if(vis[u]){
const int k=f[u].count();
inc(ans1,1ull*(qpow(2,k)-1)*qpow(2,m-k)%mod);
inc(ans2,qpow(2,m-k));
}
cout<<ans1<<' '<<ans2<<'\n';
}
posted on 2026-06-25 14:46 nullptr_qwq 阅读(19) 评论(0) 收藏 举报
浙公网安备 33010602011771号