题目链接:CF 427C
使用Kosaraju算法求出强连通分量后,易求出解
代码如下:
#include <cstdio>
#include <cstring>
typedef long long ll;
const int N = 111111;
const ll mod = 1000000007;
struct Point
{
int w, sccno;
} p[N];
struct Edge
{
int u, v, next;
} e[3 * N], d[3 * N];
int tot, tod, eh[N], ed[N];
void add1(int u, int v) {
e[tot].u = u, e[tot].v = v, e[tot].next = eh[u], eh[u] = tot++;
}
void add2(int u, int v) {
d[tod].u = u, d[tod].v = v, d[tod].next = ed[u], ed[u] = tod++;
}
int vis[N], scc_cnt, S[N], idx;
void dfs1(int u) {
if(vis[u]) return ;
vis[u] = 1;
for(int j = eh[u], v; ~j; j = e[j].next) {
v = e[j].v;
dfs1(v);
}
S[idx++] = u;
}
void dfs2(int u) {
if(p[u].sccno) return ;
p[u].sccno = scc_cnt;
for(int j = ed[u], v; ~j; j = d[j].next) {
v = d[j].v;
dfs2(v);
}
}
void find_scc(int n) {
for(int i = 1; i <= n; ++i) dfs1(i);
for(int i = n - 1; i >= 0; --i) {
if(!p[S[i]].sccno) { scc_cnt++; dfs2(S[i]); }
}
}
int cot[N], mx[N];
int main()
{
// freopen("in", "r", stdin);
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &p[i].w);
}
int m, u, v;
memset(eh, -1, sizeof eh);
memset(ed, -1, sizeof ed);
scanf("%d", &m);
for(int i = 0; i < m; ++i) {
scanf("%d%d", &u, &v);
add1(u, v);
add2(v, u);
}
find_scc(n);
memset(mx, 0x3f, sizeof mx);
for(int i = 1; i <= n; ++i) {
if(p[i].w < mx[p[i].sccno]) {
mx[p[i].sccno] = p[i].w;
cot[p[i].sccno] = 1;
}
else if(p[i].w == mx[p[i].sccno]) {
cot[p[i].sccno]++;
}
}
ll ans = 1, cost = 0;
for(int i = 1; i <= scc_cnt; ++i) {
cost += mx[i];
ans = (ans * cot[i]) % mod;
}
printf("%I64d %I64d\n", cost, ans);
return 0;
}