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取模
输入输出样例
说明
数据范围:
对于30%的数据,1<=n,m<=20;
对于10%的数据,保证不存在回路。
对于100%的数据,1<=n<=100000,1<=m<=300000。所有输入数据保证不超过10^9。
#include<bits/stdc++.h> #define REP(i, a, b) for(int i = (a); i <= (b); ++ i) #define REP(j, a, b) for(int j = (a); j <= (b); ++ j) #define PER(i, a, b) for(int i = (a); i >= (b); -- i) using namespace std; const int maxn=5e5+5; const int mod=1e9+7; template <class T> inline void rd(T &ret){ char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9'){ ret = ret * 10 + (c - '0'), c = getchar(); } } struct node{int to,nx;}p[maxn]; int vis[maxn],val[maxn],head[maxn],n,m,tot,cnt,ans,fn,dfn[maxn],low[maxn],my; void addedge(int u,int v){ p[++tot].to=v,p[tot].nx=head[u],head[u]=tot; } vector<int>v[maxn]; stack<int>sk; void tarjan(int s){ dfn[s]=low[s]=++cnt; vis[s]=1; sk.push(s); for(int i=head[s];i;i=p[i].nx){ int to=p[i].to; if(!dfn[to]){ tarjan(to); low[s]=min(low[s],low[to]); } else if(vis[to]) low[s]=min(low[s],dfn[to]); } if(dfn[s]==low[s]){ int cur; ++my; do{ cur=sk.top(); sk.pop(); vis[cur]=0; v[my].push_back(cur); }while(cur!=s); } } int main() { rd(n); fn=1; REP(i,1,n)rd(val[i]); rd(m); REP(i,1,m){ int u,v; rd(u),rd(v); addedge(u,v); } REP(i,1,n){ if(!dfn[i])tarjan(i); } REP(i,1,my){ int cur=v[i].size(),tmp=0,minn=mod; for(int j=0;j<cur;j++){ if(minn>val[v[i][j]]){ minn=val[v[i][j]]; tmp=1; } else if(minn==val[v[i][j]]) tmp++; } ans+=minn; fn=(fn%mod*tmp%mod)%mod; } cout<<ans<<' '<<fn<<endl; return 0; }