码迷,mamicode.com
首页 > 其他好文 > 详细

P2194 HXY烧情侣

时间:2018-02-11 12:28:01      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:style   乘法   tarjan   class   pac   拆点   存在   print   输入格式   

题目描述

众所周知,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
输出样例#1: 复制
3 1
输入样例#2: 复制
3
10 20 10
4
1 2
1 3
3 1
2 1
输出样例#2: 复制
10 2

说明

数据范围:

对于30%的数据,1<=n,m<=20;

对于10%的数据,保证不存在回路。

对于100%的数据,1<=n<=100000,1<=m<=300000。所有输入数据保证不超过10^9。

 

很简单,tarjan拆点,对于方案数,用乘法计数原理不难解出。

AC代码如下:

#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;
const int M=300000+5;
const int N=100000+5;
const int INF=1e9+7;
struct p{
    int to,nxt;
}e[M];
int fir[N],dfn[N],low[N],col[N],tot,num,t,x,y,n,m,mincost[N],cost[N],ans1,ans2=1,nu[N];
bool ins[N];
stack<int>s;
void add(int u,int v)
{
    tot++;
    e[tot].to=v;
    e[tot].nxt=fir[u];
    fir[u]=tot;
    return;
}
void dfs(int now)
{
    dfn[now]=low[now]=++t;
    s.push(now);
    ins[now]=1;
    for(int i=fir[now];i;i=e[i].nxt)
    if(!dfn[e[i].to]) dfs(e[i].to),low[now]=min(low[now],low[e[i].to]);
    else if(ins[e[i].to]) low[now]=min(low[now],dfn[e[i].to]);
    
    if(dfn[now]==low[now])
    {
        num++;
        col[now]=num;
        mincost[num]=cost[now];
        ins[now]=0;
        while(s.top()!=now)
        {
            col[s.top()]=num;
            mincost[num]=min(mincost[num],cost[s.top()]);
            ins[s.top()]=0;
            s.pop();
        }
        s.pop();
    }
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&cost[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    scanf("%d%d",&x,&y),add(x,y);
    for(int i=1;i<=n;i++)
    if(!dfn[i]) dfs(i);
    for(int i=1;i<=num;i++)
    ans1+=mincost[i];
    printf("%d ",ans1);
    for(int i=1;i<=n;i++)
    if(cost[i]==mincost[col[i]]) nu[col[i]]++;
    for(int i=1;i<=num;i++)
    ans2*=nu[i]%INF;
    printf("%d",ans2);
    return 0;
}

 

P2194 HXY烧情侣

标签:style   乘法   tarjan   class   pac   拆点   存在   print   输入格式   

原文地址:https://www.cnblogs.com/Alex-leaves/p/8440547.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!