Wannafly挑战赛22B.字符路径(动态规划)

链接:https://ac.nowcoder.com/acm/contest/160/B
来源:牛客网
 

字符路径

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符,问图上有几条路径满足路径上经过的边上的字符组成的的字符串去掉空格后以大写字母开头,句号 '.' 结尾,中间都是小写字母,小写字母可以为0个。

输入描述:

第一行两个整数n,m
接下来m行,每行两个整数a,b和一个字符c,表示一条起点为a,终点为b的边,边上的字符是c
1 ≤ n, m ≤ 50000
1 ≤ a < b ≤ n
c可以是大小写字母、句号 '.' 或空格(方便起见用 '_' 表示空格)

输出描述:

输出一个整数,表示答案对232取模的结果

示例1

输入

复制

6 11
1 2 A
1 2 _
3 4 _
2 4 B
2 3 a
2 3 _
2 4 b
4 5 .
3 5 .
2 5 .
5 6 _

输出

复制

16

思路:

原本还想保存到达点i的所有字符结尾的状态,这样写好像也可以,但是还有更优秀的方法。

dp[i][1]表示到达i点结束,以空格为起点的路径数

dp[i][2]表示到达i点结束,以大写字母或者小写字母为中间段的路径数,为什么大写字母归为这种状态呢?因为大写字符+小写字符,和单独的大写字符,状态都是一样的,都可以看成是以空格开头的中间部分。

dp[i][3]表示到达i点结束,以句号结尾的路径数。

转移就很好想了,代码中给了注释,可以更好的理解。

举一反三,这里还有一道差不多的状态转移,这种只记录开始,中间和结尾的状态比较常见,值得理解。

Comet oj contest #8:https://blog.csdn.net/Q755100802/article/details/99341358

C题,也是差不多的思路

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
#define pb push_back
#define mk make_pair
#define ll long long
#define u32 unsigned int
const int maxn=5e4+10;
int n,m;
vector<pair<int,char>>g[maxn];

//空格开头 1
//中间 2
//已经结尾 3
u32 dp[maxn][10];
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	rep(i,1,m){
		int a,b;
		char tmp;
		cin>>a>>b>>tmp;
		g[a].push_back(mk(b,tmp));
	}
	rep(i,1,n){
		for(int j=0;j<int(g[i].size());++j){
			int to=g[i][j].first,sig=g[i][j].second;
			if(sig<='z'&&sig>='a'){
				dp[to][2]+=dp[i][2];//小写字母一定是中间态的转移
			}
			else if(sig=='_'){
				dp[to][1]+=dp[i][1];//空格可以在任何一个位置,继承所有状态
				dp[to][2]+=dp[i][2];
				dp[to][3]+=dp[i][3];
				//空格还可以单独成为一个合法路径,+1
				dp[to][1]++;
			}
			else if(sig<='Z'&&sig>='A'){
				dp[to][2]+=dp[i][1];//大写字符,出现在空格字符之后,状态为中间
				//单独的大写字符也满足状态
				dp[to][2]++;
			}
			else dp[to][3]+=dp[i][2];//结尾状态,为中间态+句号
		}
	}
	u32 ans=0;
	rep(i,1,n)ans+=dp[i][3];
	cout<<ans<<endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值