CF427C Checkposts
Description
Solution
首先吐槽一句:不知道这题是怎么评到紫的。
观察题意:
如果有一个检查站在 \(i\) 路口,保护 \(j\) 的条件是:\(i==j\) 或者警察巡逻车可以从 \(i\) 走到 \(j\),并且能回到 \(i\)。
这不就是让我们求强连通分量吗?
确实是的,我们缩个点,对于每一个强连通分量记录一下最小的点权权值是多大。
然后把所有强连通分量里的最小点权加起来就是我们第一问的答案。
那第二问怎么算呢?
也很简单,我们把每个强连通分量里最小点权出现次数统计一下,然后求个积即可。
观察到这题要取模,取模就取模吧。
\(WA\)?!怎么回事?
看了一眼讨论区,发现第一问不用取模……
证明了看英文题面的重要性……
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
inline int read(){
int x = 0;
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
const ll mod = 1e9 + 7;
const int N = 1e5 + 10;
const int M = 3e5 + 10;
int n, m;
int val[N];
struct node{
int v, nxt;
}edge[M << 1];
int head[N], tot;
inline void add(int x, int y){
edge[++tot] = (node){y, head[x]};
head[x] = tot;
}
int dfn[N], low[N], tim;
int stk[N], top, vis[N];
int cnt;
ll mins[N], num[N];
inline void tarjan(int x){
dfn[x] = low[x] = ++tim;
stk[++top] = x;
vis[x] = 1;
for(int i = head[x]; i; i = edge[i].nxt){
int y = edge[i].v;
if(!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if(vis[y]) low[x] = min(low[x], dfn[y]);
}
if(low[x] == dfn[x]){
cnt++;
int k;
do{
k = stk[top];
if(mins[cnt] == val[k]) num[cnt]++;
else if(mins[cnt] > val[k]) mins[cnt] = val[k], num[cnt] = 1;
vis[k] = 0;
top--;
}while(x != k);
}
}
int main(){
n = read();
for(int i = 1; i <= n; ++i)
val[i] = read();
m = read();
for(int i = 1; i <= m; i++){
int u = read(), v = read();
add(u, v);
}
memset(mins, 0x3f, sizeof(mins));
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
ll ans = 0, sum = 1;
for(int i = 1; i <= cnt; ++i)
ans += mins[i], sum = sum * num[i] % mod;
printf("%lld %lld\n", ans, sum);
return 0;
}