zoukankan      html  css  js  c++  java
  • 题解 CF427C 【Checkposts】

    [ ext{关于题意} ]

    (quad)因为点i能保护j的条件是i可以到达j且j可以返回i,这不就是强连通分量的定义吗?所以考虑缩点,将每个强连通分量缩成一个点,缩点后每个强连通分量中只需取一个点,所以记录每个强连通分量中最小点权及其数量,最后最低成本就是每个强连通分量最小点权之和,方案数是最小点权数量之积。

    (quad)别忘了开long long,最后方案数要对1e9+7取模。

    (quad)如果还有什么不懂的地方就看看代码吧

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<map>
    #include<stack>
    #include<algorithm>
    #include<vector>
    #define re register int
    #define int long long
    #define il inline
    #define next ne
    using namespace std;
    il int read()				//快速读入
    {
    	int x=0,minus=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){
    		if(ch=='-')minus=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*minus;
    }
    const int N=1e5+5,MOD=1e9+7;
    int n,m,a[N],next[N*3],go[N*3],head[N];
    int low[N],dfn[N],c[N],s[N],p[N],l[N],tot,cnt,ans,ans1=1;
    il void Add(int x,int y)		//链式前向星存图
    {
    	next[++tot]=head[x];
    	head[x]=tot;
    	go[tot]=y;
    }
    stack<int>q;
    il void Tarjan(int x)		 	//Tarjan缩点
    {
    	dfn[x]=low[x]=++cnt;
    	q.push(x);
    	for(re i=head[x];i;i=next[i])
    	{
    		int y=go[i];
    		if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
    		else if(!c[y])low[x]=min(low[x],dfn[y]);
    	}
    	if(dfn[x]==low[x])
    	{
    		c[x]=++c[0];
    		s[c[0]]=a[x];p[c[0]]=1;  			//记录每个强连通分量中点权最小的,数量初始化为1
    		while(q.top()!=x)
    		{
    			c[q.top()]=c[0];
    			if(s[c[0]]==a[q.top()])p[c[0]]++;		  	 //如果有一样小的点权,数量+1
    			else if(s[c[0]]>a[q.top()])s[c[0]]=a[q.top()],p[c[0]]=1; //如果有更小的点权就更新,数量变为1
    			q.pop();
    		}
    		q.pop();
    	}
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<=n;i++)a[i]=read();
    	m=read();
    	for(re i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		Add(x,y);
    	}
    	for(re i=1;i<=n;i++)
    	if(!dfn[i])Tarjan(i);
    	for(re i=1;i<=c[0];i++)
    	{
    		ans+=s[i];		//最小点权之和
    		ans1*=p[i]%MOD;		//数量之积
    	}
    	printf("%lld %lld",ans,ans1%MOD);
    	return 0;
    }
    

    [ ext{后话} ]

    此题有双倍经验哦,P2194 HXY烧情侣

    临近CSP复赛,祝大家RP++。

    写题解不易,帮忙点个赞吧。

  • 相关阅读:
    Ubuntu开发环境配置
    win7和Ubuntu16.04之间相互远程控制
    QT学习之usb摄像头采集(Opencv+QT)[cvCapture,IplImage,QImage]
    Opencv 图像畸变矫正(after 相机标定, 获得内参和畸变参数)
    opencv角点检测、棋盘格检测、亚像素cvFindCornerSubPix()
    开始学习机加工钣金加工
    今夜的硬件之旅
    关于做实验
    机器学习部分题目
    ubuntu18.10配置git和github
  • 原文地址:https://www.cnblogs.com/FarkasW/p/13916590.html
Copyright © 2011-2022 走看看