CF467D Fedor and Essay

由于某些字符,会我转为你,你转为他,他转为我,形成一个环,所以先缩点后得到一个DAG森林。
对于森林里的每棵树,做一次取最大值的dp即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=6e5+5;
int n,m,tot,ans1,ans2,id[N],dp1[N],dp2[N],u[N],v[N],nn;
char str[N];
bool vis[N];
int now,top,col,dfn[N],low[N],sta[N],color[N];
struct number{int v,len;}num[N];
map<string,int>mp;
int cnt,head[N];
struct edge{int next,to;}e[N<<1];

inline void add(int u,int v)
{
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}

void tarjan(int u)
{
	dfn[u]=low[u]=++now;
	sta[++top]=u;
	for (register int i=head[u]; i; i=e[i].next)
	if (!dfn[e[i].to])
	{
		tarjan(e[i].to);
		low[u]=min(low[u],low[e[i].to]);
	}
	else if (!color[e[i].to]) low[u]=min(low[u],low[e[i].to]);
	if (dfn[u]==low[u])
	{
		col++;
		while (sta[top]!=u) 
		{
			int now=sta[top];
			if (num[now].v<dp1[col] || num[now].v==dp1[col] && num[now].len<dp2[col]) 
			dp1[col]=num[now].v,dp2[col]=num[now].len; 
			color[sta[top]]=col;
			top--;	
		}
		int now=sta[top];
		if (num[now].v<dp1[col] || num[now].v==dp1[col] && num[now].len<dp2[col]) 
		dp1[col]=num[now].v,dp2[col]=num[now].len; 
		color[sta[top]]=col;
		top--;	
	}
}

void dfs(int u)
{
	if (vis[u]) return;
	vis[u]=true;
	for (register int i=head[u]; i; i=e[i].next)
	{
		dfs(e[i].to);
		if (dp1[e[i].to]<dp1[u] || dp1[e[i].to]==dp1[u] && dp2[e[i].to]<dp2[u]) 
		dp1[u]=dp1[e[i].to],dp2[u]=dp2[e[i].to];
	}
}

signed main(){
	int inf=1e18;
	for (register int i=1; i<=1e5; ++i) dp1[i]=dp2[i]=inf;
	scanf("%lld",&n);
	for (register int i=1; i<=n; ++i)
	{
		scanf("%s",str);
		int len=strlen(str);
		int now=0;
		for (register int j=0; j<len; ++j)
		{
			if (str[j]>='A' && str[j]<='Z') str[j]=str[j]-'A'+'a';
			if (str[j]=='r') now++;
		}
		int t=mp[str];
		if (!t) t=mp[str]=++tot;
		num[t].len=len; num[t].v=now;
		id[i]=t;
	}
	scanf("%lld",&m);
	while (m--)
	{
		scanf("%s",str);
		int len=strlen(str);
		int now=0;
		for (register int i=0; i<len; ++i)
		{
			if (str[i]>='A' && str[i]<='Z') str[i]=str[i]-'A'+'a';
			if (str[i]=='r') now++;
		}
		int x=mp[str];
		if (!x) x=mp[str]=++tot;
		num[x].len=len; num[x].v=now;
		scanf("%s",str);
		len=strlen(str);
		now=0;
		for (register int i=0; i<len; ++i)
		{
			if (str[i]>='A' && str[i]<='Z') str[i]=str[i]-'A'+'a';
			if (str[i]=='r') now++;
		}
		int y=mp[str];
		if (!y) y=mp[str]=++tot;
		num[y].len=len; num[y].v=now;
		add(x,y);
		u[++nn]=x; v[nn]=y;
	}
	for (register int i=1; i<=tot; ++i) if (!dfn[i]) tarjan(i);
	cnt=0; memset(head,0,sizeof(head));
	for (register int i=1; i<=nn; ++i)
	if (color[u[i]]!=color[v[i]]) add(color[u[i]],color[v[i]]);
	
	for (register int i=1; i<=n; ++i)
	{
		dfs(color[id[i]]);
		ans1+=dp1[color[id[i]]];
		ans2+=dp2[color[id[i]]];
	}
	printf("%lld %lld\n",ans1,ans2);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值