记录编号 318226 评测结果 AAAAAAAAAA
题目名称 膜法师 最终得分 100
用户昵称 GravatarLOSER 是否通过 通过
代码语言 C++ 运行时间 2.201 s
提交时间 2016-10-09 06:39:53 内存使用 69.93 MiB
显示代码纯文本
/*
  Name: 枪战 
  Author: Loser? 
  Date: 02/10/16 20:24
  Description: 
		考试时被坑了半天 以为是简单的缩点
		但其实是有贪心的感觉
		1>  求最小值
			即活着(入度为零)的人数最多
 			此点肯定活着 所以必须开枪 如果因此 多了一个入度为零的点 则压入队列
			到最后暴力判环即可
		2> 求最大值 
			 也就是 如果是一个点 则为 1
			 如果是一个环 则为 num-1
			 else {
				反向建图 此时为一棵树 (缩完点后)
				即可求解		
			} 
*/
#include<cstdio>
#include<queue>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
#define maxn 1000010
#define MIN(a,b) (a<b?a:b)
int n,d[maxn],to[maxn],rd[maxn];
struct Edge{int to,next,from;}e[maxn<<1],a[maxn];
int lena,heada[maxn],len,head[maxn];
void Addedge(int x,int y){
	e[++len].to=y;
	e[len].from=x;
	e[len].next=head[x];
	head[x]=len;
}
void Insert(int x,int y){
	a[++lena].to=y;
	a[lena].from=x;
	a[lena].next=heada[x];
	heada[x]=lena;	
}
bool Check[maxn];
stack<int> qq;
int low[maxn],Dfn[maxn],Time,cnt,Belong[maxn],num[maxn];
void Dfs(int x){
	Check[x]=1; qq.push(x);
	low[x]=Dfn[x]=++Time; 
	for(int i=head[x];i;i=e[i].next){
		int y=e[i].to;
		if(!Dfn[y]){
			Dfs(y);
			low[x]=MIN(low[y],low[x]);	
		}
		else if(Check[y])low[x]=MIN(Dfn[y],low[x]);
	}
	if(low[x]==Dfn[x]){
		int k; cnt++;
		do{
			k=qq.top();qq.pop();Check[k]=0;
			Belong[k]=cnt; num[cnt]++;
		}while(k^x);
	}
}
int Work(int x,int &tot){
	int temp=0;	
	tot+=num[x];
	for(int i=heada[x];i;i=a[i].next){
		int y=a[i].to;
		if(!d[y]){tot++;temp++;continue;}
		else temp+=Work(y,tot);	
	}	
	return temp;
}
int main(){
	freopen("maf.in","r",stdin); freopen("maf.out","w",stdout);
	int __size__=128<<20;
char *__p__=(char*)malloc(__size__)+__size__;
__asm__("movl %0, %%esp\n"::"r"(__p__));
	queue<int> q;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&to[i]);
		d[to[i]]++; Addedge(to[i],i); 
	}
	for(int i=1;i<=n;i++){
		if(!d[i])q.push(i);	
	}
	while( !q.empty() ){
		int k=q.front(); q.pop();
		int t=to[k];
		if(!Check[t]){
			Check[t]=1;	
			if(--d[to[t]]==0)q.push(to[t]);	
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(!Check[i]){
			int x=i,num=0;
			if(Check[to[i]])num=2;
			while(!Check[to[x]]){
				Check[to[x]]=1;
				x=to[x];	
				num++;
			}		
			ans+=num/2;
		}	
	}
	printf("%d ",n-ans);
	memset(Check,0,sizeof(Check));
	for(int i=1;i<=n;i++){
		if(!Dfn[i])Dfs(i);	
	}
	memset(d,0,sizeof(d));
	for(int i=1;i<=len;i++){
		int u=e[i].from,v=e[i].to;
		if(Belong[u]==Belong[v])continue;
		Insert(Belong[u],Belong[v]);	
		d[Belong[u]]++; rd[Belong[v]]++;
	}
	ans=0;
	memset(Dfn,0,sizeof(Dfn));
	for(int i=1;i<=cnt;i++){
		if(!rd[i]){
			int tot=0;
			if(!d[i]){
				if(num[i]==1)ans++;
				else ans+=num[i]-1;
			}
			else{
				int data=Work(i,tot);
				ans+=tot-data;	
			}	
		}
	}
	printf("%d\n",ans);
	getchar(); getchar();
	return 0;	
}