P2194 HXY烧情侣 题解

· · 题解

其实我本人是反对烧情侣的

因为我喜欢一个特勇的女孩纸,但是总是泡不到(OIer共性)

好了,进入正题

此题为Tarjan

我就说一下方案数怎么算

就是乘法原理:各个强连通分量中最小花费点的个数相乘

上代码:

#include<bits/stdc++.h>//万能头
#define maxn 100001
#define maxm 300005
using namespace std;
struct Edge{
    int nex,to;
}edge[maxm];
int low[maxn],dfn[maxn],k[maxm],c[maxm],du[maxm],hea[maxm],stac[maxn],ins[maxn],a[maxn];
int top,tot,n,m,num,cnt;
long long ans1,ans2=1,mo=1e9+7;//ans1,ans2一定要longlong不然可能会炸
vector<int>scc[maxm];
void add(int x,int y)
{
    edge[++tot].nex=hea[x];
    edge[tot].to=y;
    hea[x]=tot; 
}//存下一条<x.y>的弧
void tarjan(int x)//Tarjan1经典模板
{
    dfn[x]=low[x]=++num;
    stac[++top]=x;ins[x]=1;
    for(int i=hea[x];i;i=edge[i].nex)
    {
        int y=edge[i].to;
        if(!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(ins[y])
        {
            low[x]=min(low[x],dfn[y]);
        }
    }
    if(low[x]==dfn[x])
    {
        int z;cnt++;
        do{
            z=stac[top--];ins[z]=0;c[z]=cnt;k[cnt]++;scc[cnt].push_back(z);
        }while(x!=z);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);//存边
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])  tarjan(i);//如果未被搜索就Tarjan
    }
    for(int i=1;i<=cnt;i++)
    {
        int coun=1,x=0x3fffffff;
        int len=scc[i].size();
        for(int j=0;j<len;j++)
        {
            if(a[scc[i][j]]==x) coun++;//如果一样就++
            if(a[scc[i][j]]<x)
            {
                x=a[scc[i][j]];
                coun=1;
            }//如果小于就重置
        }
        ans1+=x;
        ans2*=coun;
        ans2%=mo;
    }
    cout<<ans1<<" "<<ans2;
    return 0;
}

最后,祝各位OIer都能A过此题(不抄题解),也祝你们能够追到自己心仪的妹子!

管理大大给个通过呗