【CodeForces】467D Fedor and Essay 强连通+DP

传送门:【CodeForces】467D Fedor and Essay


题目分析:首先将单词离散化(我用的map),然后根据题意对单词u能替换成单词v的我们建有向边(u,v),然后跑一次强连通,在强连通里面如果子节点比父节点更优则用子节点的信息来取代父节点的。然后当dfn[ u ] == low[ u ]时,也就是形成一个强连通的时候,很容易可以得知u的信息一定是u能取到的最优的转化(已经用子节点更新自己了,等于所有子节点的信息都以上传,可以自己yy一下),然后强连通的缩点(就当他缩点了吧)同时用u的信息更新所有的该强连通中其他点的信息。

tarjan遍历选取第一个点遍历的先后顺序是不会影响结果的,可以yy一下。

最后答案只要累加该单词替换成的单词的信息即可(当然可能有的单词不替换)。

是不是很简单?但是有一个坑点,就是会爆int!


这个应该也算DP吧?。。既然cf都说是DP了那我也就不客气了,我贫瘠的DP终于又补充了一道~


代码如下:


#include <map>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define F( i ) ( ( ( i ) - 1 ) % n + 1 )

const int MAXN = 100005 ;
const int MAXE = 100005 ;

struct Edge {
	int v ;
	Edge* next ;
} E[MAXE] , *H[MAXN] , *edge ;

struct Node {
	int idx ;
	int Rnum , Len ;
	Node () {}
	Node ( int N , int L , int idx ) : Rnum ( N ) , Len ( L ) , idx ( idx ) {}
	bool operator < ( const Node& a ) const {
		if ( Rnum != a.Rnum ) return Rnum < a.Rnum ;
		return Len < a.Len ;
	}
} word[MAXN] , a[MAXN] ;

int dfn[MAXN] , low[MAXN] , dfs_clock ;
int scc[MAXN] , scc_cnt ;
map < string , int > mp ;
int S[MAXN] , top ;
char buf[5 * MAXN] ;
int point ;
int n , m ;

void clear () {
	top = 0 ;
	edge = E ;
	point = 0 ;
	mp.clear () ;
	scc_cnt = 0 ;
	dfs_clock = 0 ;
	clr ( H , 0 ) ;
	clr ( dfn , 0 ) ;
	clr ( scc , 0 ) ;
}

void addedge ( int u , int v ) {
	edge -> v = v ;
	edge -> next = H[u] ;
	H[u] = edge ++ ;
}

void tarjan ( int u ) {
	dfn[u] = low[u] = ++ dfs_clock ;
	S[top ++] = u ;
	travel ( e , H , u ) {
		int v = e -> v ;
		if ( !dfn[v] ) {
			tarjan ( v ) ;
			low[u] = min ( low[u] , low[v] ) ;
		} else if ( !scc[v] ) low[u] = min ( low[u] , dfn[v] ) ;
		if ( a[v] < a[u] ) a[u] = a[v] ;
	}
	if ( low[u] == dfn[u] ) {
		++ scc_cnt ;
		do {
			int v = S[-- top] ;
			scc[v] = scc_cnt ;
			a[v] = a[u] ;
		} while ( S[top] != u ) ;
	}
}

Node read () {
	int len = 0 , num = 0 ;
	char c ;
	while ( ( c = getchar () ) == ' ' || c == '\n' ) ;
	if ( c <= 'Z' ) c += 97 - 'A' ;
	if ( c == 'r' ) ++ num ;
	buf[len ++] = c ;
	while ( ( c = getchar () ) >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' ) {
		if ( c <= 'Z' ) c += 97 - 'A' ;
		buf[len ++] = c ;
		if ( c == 'r' ) ++ num ;
	}
	buf[len] = 0 ;
	map < string , int > :: iterator it = mp.find ( buf ) ;
	if ( it != mp.end () ) return Node ( num , len , it -> second ) ;
	mp.insert ( map < string , int > :: value_type ( buf , point ) ) ;
	a[point] = Node ( num , len , 0 ) ;
	return Node ( len , num , point ++ ) ;
}

void solve () {
	clear () ;
	rep ( i , 0 , n ) word[i] = read () ;
	scanf ( "%d" , &m ) ;
	while ( m -- ) {
		int u = read ().idx ;
		int v = read ().idx ;
		addedge ( u , v ) ;
	}
	rep ( i , 0 , point ) if ( !dfn[i] ) tarjan ( i ) ;
	LL ans1 = 0 , ans2 = 0 ;
	rep ( i , 0 , n ) {
		ans1 += a[word[i].idx].Rnum ;
		ans2 += a[word[i].idx].Len ;
	}
	printf ( "%I64d %I64d\n" , ans1 , ans2 ) ;
}

int main () {
	while ( ~scanf ( "%d" , &n ) ) solve () ;
	return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值