Codeforces Round #244 (Div. 2) 427C Checkposts (强连通分量 tarjan模板)

时间限制:2S / 空间限制:256MB

【在线测试提交传送门】

【问题描述】

    Your city has n junctions. There are m one-way roads between the junctions. As a mayor of the city, you have to ensure the security of all the junctions.

To ensure the security, you have to build some police checkposts. Checkposts can only be built in a junction. A checkpost at junction i can protect junction j if either i = j or the police patrol car can go to j from i and then come back to i.

Building checkposts costs some money. As some areas of the city are more expensive than others, building checkpost at some junctions might cost more money than other junctions.

You have to determine the minimum possible money needed to ensure the security of all the junctions. Also you have to find the number of ways to ensure the security in minimum price and in addition in minimum number of checkposts. Two ways are different if any of the junctions contains a checkpost in one of them and do not contain in the other.
   作为市长,你的城市有n个交叉路口,为了保户这些路口的安全,需要建若干个安全亭,这些安全亭只能建在交叉路口,建立在第i个交叉路口的安全亭能保护交叉路口j的条件是:i=j或者警车能从路口i开到j,并且能从j开回到i。
   建在不同交叉路口的安全亭可能需要不同的费用,请计算最小的花费,使得每个交叉路口都得到保护。另外请计算,在每个交叉路口都得到保护的情况下,费用最低且安全亭个数最少的方案数。当两个方案中有任意一个交叉路口的安全亭不同,则视为不同。

【输入格式】

In the first line, you will be given an integer n, number of junctions (1 ≤ n ≤ 10^5). In the next line, n space-separated integers will be given. The ith integer is the cost of building checkpost at the ith junction (costs will be non-negative and will not exceed 10^9).

The next line will contain an integer m (0 ≤ m ≤ 3*10^5). And each of the next m lines contains two integers ui and vi (1 ≤ ui, vi ≤ n; u ≠ v). A pair ui, vi means, that there is a one-way road which goes from ui to vi. There will not be more than one road between two nodes in the same direction.
第一行,一个整数n(1 ≤ n ≤ 10^5),表示交叉路口的数量。
第二行,n个正整数,依次表示在各个交叉路口建安全亭的费用,费用不超过10^9。
接下来一行,一个整数m(0 ≤ m ≤ 3*10^5);
接下来m行,每行两个整数ui和vi(1 ≤ ui, vi ≤ n; u ≠ v),表示一条从ui到vi的有向边。数据不会出现重边。

【输出格式】

Print two integers separated by spaces. The first one is the minimum possible money needed to ensure the security of all the junctions. And the second one is the number of ways you can ensure the security modulo 1000000007 (10^9 + 7).
输出共一行,两个整数,分别表示最小费用和方案数(对10^9 + 7求余)。

【输入样例1】

3
1 2 3
3
1 2
2 3
3 2

【输出样例1】

3 1

【输入样例2】

5
2 8 0 6 0
6
1 4
1 3
2 4
3 4
4 5
5 1

【输出样例2】

8 2

【输入样例3】

10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9

【输出样例3】

15 6

【输出样例4】

2
7 91
2
1 2
2 1

【输出样例4】

7 1

【题目来源】

Codeforces 427C

【解题思路】

强连通分量直接tarjan搞,对每个取权值最小的然后判断有没有权值一样的,然后乘法计数原理

【参考代码】

#include <cstdio>
#include <algorithm>
#include <vector>
#include <stack>
#define ll long long
using namespace std;
int const INF = 0x3fffffff;
int const MOD = 1e9 + 7;
int const MAX = 1e5 + 5;
int n, m, a[MAX];
int cur, dfn[MAX], low[MAX];
bool ins[MAX];
vector <int> vt[MAX];
stack <int> stk;
ll ans, tot;

void Tarjan(int u)
{
    dfn[u] = low[u] = ++cur;
    stk.push(u); 
    ins[u] = true;
    for(int i = 0; i < (int)vt[u].size(); i++) 
    {
        int v = vt[u][i];
        if(!dfn[v]) 
            Tarjan(v);
        if(ins[v]) 
            low[u] = min(low[u], low[v]);
    }
    if(dfn[u] == low[u]) 
    {
        int mi = INF, cnt = 0, v;
        do
        {
            v = stk.top(); 
            stk.pop();
            ins[v] = false;
            if(a[v] < mi) 
            { 
                mi = a[v]; 
                cnt = 0; 
            }
            if(a[v] == mi) 
                cnt ++;
        }while(u != v);
        ans += mi; 
        tot = ((tot % MOD) * (cnt % MOD)) % MOD;
    }
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    scanf("%d", &m);
    while(m--) 
    {
        int x, y; 
        scanf("%d %d", &x, &y);
        vt[x].push_back(y);
    }
    tot = 1;
    for(int i = 1; i <= n; i++)
        if(!dfn[i])
            Tarjan(i);
    printf("%I64d %I64d\n", ans, tot);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值