https://codeforces.com/contest/1138/problem/E
有n个城市(1e5),有m条单向边(1e5),每一周有d天(50),对于每个城市假如在某一天为1表示这天城市博物馆开放,反之闭馆,问你最多能去多少个博物馆
#include<bits/stdc++.h>
#define N 100005
#define D 55
#define MAXN N*D
using namespace std;
int hd[MAXN],nt[MAXN],to[MAXN],cnt;
int hd2[MAXN],nt2[MAXN],to2[MAXN],cnt2;
int dfn[MAXN],low[MAXN],vis[MAXN],stk[MAXN],top,Time,scc,blk[MAXN];
int dp[MAXN],sz[MAXN];
int n,m,d,u,v;
char s[N][D];
int id(int a,int b){
return (a-1)*d+b%d+1;
}
void add(int u,int v){
nt[++cnt]=hd[u];to[cnt]=v;hd[u]=cnt;
}
void add2(int u,int v){
nt2[++cnt2]=hd2[u];to2[cnt2]=v;hd2[u]=cnt2;
}
void tarjan(int u){
dfn[u]=low[u]=++Time;
stk[++top]=u;vis[u]=1;
for(int i=hd[u];i;i=nt[i]){
int v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
++scc;
for(;;){
int x=stk[top];top--;
vis[x]=0;blk[x]=scc;
if(x==u)break;
}
}
}
void dfs(int u){
if(dp[u])return;
for(int i=hd2[u];i;i=nt2[i]){
int v=to2[i];
dfs(v);
dp[u]=max(dp[u],dp[v]);
}
dp[u]+=sz[u];
return;
}
int main(){
scanf("%d%d%d",&n,&m,&d);
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
for(int j=0;j<d;j++)
add(id(u,j),id(v,(j+1)%d));
}
for(int i=1;i<=n;i++)scanf("%s",s[i]);
for(int i=1;i<=n*d;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;i++){
for(int j=0;j<d;j++){
int x=id(i,j);
if(s[i][j]=='1'&&vis[blk[x]]!=i){
sz[blk[x]]++;
vis[blk[x]]=i;
}
for(int k=hd[x];k;k=nt[k]){
int v=to[k];
if(blk[v]!=blk[x])add2(blk[x],blk[v]);
}
}
}
dfs(blk[1]);
printf("%d",dp[blk[1]]);
}
Codeforces Round #545 (Div. 2) E 强连通块 + dag上求最大路径 + 将状态看成点建图
原文:https://www.cnblogs.com/VIrtu0s0/p/10809476.html