題目描述
衆所周知,HXY已經加入了FFF團。現在她要開始喜(sang)聞(xin)樂(bing)見(kuang)地燒情侶了。這裏有n座電影院,n對情侶分別在每座電影院裏,然後電影院裏都有汽油,但是要使用它需要一定的費用。m條單向通道連接相鄰的兩對情侶所在電影院。然後HXY有個絕技,如果她能從一個點開始燒,最後回到這個點,那麼燒這條迴路上的情侶的費用只需要該點的汽油費即可。並且每對情侶只需燒一遍,電影院可以重複去。然後她想花盡可能少的費用燒掉所有的情侶。問最少需要多少費用,並且當費用最少時的方案數是多少?由於方案數可能過大,所以請輸出方案數對1e9+7取模的結果。
(注:這裏HXY每次可以從任何一個點開始走迴路。就是說一個迴路走完了,下一個開始位置可以任選。所以說不存在燒不了所有情侶的情況,即使圖不連通,HXY自行選擇頂點進行燒情侶行動。且走過的道路可以重複走。)
輸入輸出格式
輸入格式:
第一行,一個整數n。
第二行,n個整數,表示n個情侶所在點的汽油費。
第三行,一個整數m。
接下來m行,每行兩個整數xi,yi,表示從點xi可以走到yi。
輸出格式:
一行,兩個整數,第一個數是最少費用,第二個數是最少費用時的方案數對1e9+7取模
輸入輸出樣例
輸入樣例1
3
1 2 3
3
1 2
2 3
3 2
輸入樣例2
3
10 20 10
4
1 2
1 3
3 1
2 1
輸出樣例1
3 1
輸出樣例2
10 2
說明
數據範圍:
對於30%的數據,1<=n,m<=20;
對於10%的數據,保證不存在迴路。
對於100%的數據,1<=n<=100000,1<=m<=300000。所有輸入數據保證不超過10^9。
tarjan 求 scc 的裸題,每個 scc 裏取個最小值, Σscc_min[ i ] 爲第一問答案,記錄下每個 scc 裏最小的點的個數,乘起來是第二問答案。
代碼如下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define ll long long
using namespace std;
const int sz = 800010;
const int mod = 1e9+7;
ll head[sz],nxt[sz],dist[sz],l[sz];
ll low[sz],dfn[sz],scc_num,dfs_clock;
ll scc_min[sz];
struct gtnd
{
ll p,num;
bool operator <(const gtnd &a)const
{
return num < a.num;
}
}scc[sz];
int len;
int tot = 1;
ll ans_min;
ll ans_time = 1;
stack < int > s;
int n,m;
void build(int f,int t)
{
l[tot] = t;
nxt[tot] = head[f];
head[f] = tot ++;
}
ll read()
{
ll x = 0 , f = 1;
char in = getchar();
while(in < '0' || in > '9')
{
if(in == '-')
f = -1;
in = getchar();
}
while('0' <= in && in <= '9')
{
x = x * 10 + in - '0';
in = getchar();
}
return x * f;
}
void start_work()
{
n = read();
for(int i = 1 ; i <= n ; i ++)
dist[i] = read();
m = read();
for(int i = 1 ; i <= m ; i ++)
{
int xi = read() , yi = read();
build(xi,yi);
}
}
int tarjan(int u)
{
dfn[u] = low[u] = dfs_clock ++;
s.push(u);
for(int i = head[u] ; i ; i = nxt[i])
{
int v = l[i];
if(!dfn[v])
{
low[v] = tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!scc[v].num)
low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u])
{
scc_num ++;
while(12 < 450)
{
if(s.empty())
break;
int v = s.top();
s.pop();
scc[v].num = scc_num;
scc[v].p = v;
if(u == v)
break;
}
}
return low[u];
}
void make_tarjan()
{
for(int i = 1 ; i <= n ; i ++)
if(!dfn[i])
tarjan(i);
sort(scc+1,scc+n+1);
}
void work()
{
for(int i = 1 ; i <= n ; i ++)
{
int j;
for(j = i + 1 ; j <= n + 1 ; j ++)
if(scc[i].num != scc[j].num)
break;
j --;
int minn = 2147483641 , minn_time = 0;
for(int k = i ; k <= j ; k ++)
if(minn > dist[scc[k].p])
minn = dist[scc[k].p] , minn_time = 1;
else if(minn == dist[scc[k].p])
minn_time ++;
scc_min[++len] = minn_time;
ans_min += minn;
i = j;
}
for(int i = 1; i <= len ; i ++)
ans_time *= scc_min[i] % mod , ans_time %= mod;
printf("%lld %lld\n",ans_min,ans_time);
}
int main()
{
start_work();
make_tarjan();
work();
return 0;
}