洛谷P2194 HXY燒情侶

題目描述

衆所周知,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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章