CF1137C 【Museums Tour】

Rainbow_qwq

2020-06-01 16:33:02

Solution

[CF1137C Museums Tour ](https://www.luogu.com.cn/problem/CF1137C) --- # 思路 分层图 & 强连通缩点。 注意一些要点: 1. 只要能走,旅行者可以走无数天。 2. 一周 $d$ 天的开放是循环的。 于是我们可以想到拆点,把一个点 $u$ 拆成 $[u,0],[u,1],\dots,[u,d-1]$,这样每个点的博物馆对应一个确定的状态 开/关。 对于原图上的边 $u\to v$ ,拆成 $d$ 条边 $[u,i]\to [v,(i+1)\bmod d] (0\le i\le d-1)$ ,相当于今天的 $u$ 向明天的 $v$ 连边。 然后从 $[1,0]$ 开始跑一次最长路就可以了?不行,图上还有环。 于是想到 Tarjan 缩点,每个强连通分量的点权为 **这个强连通分量中开启的不同博物馆个数**。 缩点后形成一个 DAG 就可以直接 dfs 求最长路了。 Q: 会不会重复统计相同博物馆? 不会的,假设 $[u,i]$ 与 $[u,j]$ 在不同强连通分量且 $[u,i]$ 可到 $[u,j]$ ,那么从 $[u,j]$ 也能走到 $[u,i]$ 。 upd:上面那句话的证明如下: 如果存在 $[i,a]\to [i,a+x]$ ,那么 $[i,a+x]\to[i,a+x+x]$ , 以此类推 $[i,a+x]\to [i,(a+x*d)\ \bmod \ d]$ 而 $[i,(a+x*d)\ \bmod \ d]$ 就是 $[i,a]$ 也就是说 如果 $[i,a]\to [i,a+x]$ ,那么 $[i,a+x]\to[i,a]$ 时间/空间复杂度 $O(nd)$ 。 这题思路还是挺顺的( # 代码 有点难写,还要注意不被卡空间( 注意:计算点权的时候,vis 数组不能 memset 。 ```cpp #pragma GCC optimize(2) #include<bits/stdc++.h> #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) using namespace std; inline int read() { char c=getchar();int x=0;bool f=0; for(;!isdigit(c);c=getchar())f^=!(c^45); for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48); if(f)x=-x;return x; } #define maxn 100005 #define N 100005*50 int n,m,k; long long sta[maxn]; struct edge{ int to,nxt; }e[N],e2[N]; int tot,tot2,head[N],head2[N]; inline void adde(int u,int v){ e[++tot]=(edge){v,head[u]}; head[u]=tot; } inline void adde2(int u,int v){ e2[++tot2]=(edge){v,head2[u]}; head2[u]=tot2; } int idx,scc,bel[N],dfn[N],low[N]; int f[N],val[N]; bool ins[N],vis[N]; stack<int>s,q; inline void tarjan(int u){ dfn[u]=low[u]=++idx; ins[u]=1;s.push(u); for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); }else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]!=dfn[u])return; ++scc;int v; do{ v=s.top();s.pop(); ins[v]=0,bel[v]=scc; int x=(v-1)%n+1,day=(v-1)/n; // x:哪个城市 // day:哪天 if(!vis[x] && (sta[x]>>day&1)){ val[scc]++,vis[x]=1; q.push(x); } }while(u!=v); while(!q.empty())vis[q.top()]=0,q.pop(); } inline int P(int i,int j){ return j*n+i; } //dfs 最长路 int dfs(int u) { if(vis[u])return f[u]; vis[u]=1; for(int i=head2[u];i;i=e2[i].nxt){ int v=e2[i].to; f[u]=max(f[u],dfs(v)); } return f[u]+=val[u]; } int main() { n=read(),m=read(),k=read(); For(i,1,m){ int u=read(),v=read(); For(j,0,k-1)adde(P(u,j),P(v,(j+1)%k)); } char ch; For(i,1,n) For(j,0,k-1){ while(!isdigit(ch=getchar())); sta[i]|=1ll*(ch-'0')<<j; } tarjan(1); For(i,1,n*k) { if(!dfn[i])continue; int u=bel[i]; for(int j=head[i];j;j=e[j].nxt){ int v=e[j].to; if(!dfn[v])continue; v=bel[v]; if(u!=v)adde2(u,v); } } cout<<dfs(bel[1]); return 0; } ```