Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )
链接:https://ac.nowcoder.com/acm/contest/160/B
来源:牛客网
题目描述
给一个含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
思路:
首先进行拓扑排序,
为什么要进行拓扑排序呢?
我们知道因为这是一个有向图,拓扑排序后不存在两个节点a,b 拓扑序中b在a的后面,而b有一条边指向a,这是不存在的。
因为在dp的过程中,我们的后一个状态是根据前一个状态转移过来的,这就要求上一个状态一定是不能再有改变的了。
即动态规划的无后效性:
当前的值只和当前的状态有关,和之前怎么来到这个状态和之后怎么去其他状态都无关。
那么我们再拓扑排序之后,就可以根据有向边的字符类对状态进行转移。
我们定义dp状态如下:
dp[i][0] : 以i节点为结尾的路径中,只包括空格的路径个数。
dp[i][1] : 以i节点为结尾的路径中,去掉空格后,第一个字符为大写字符,后面均为小写字符串的路径个数。
dp[i][0] : 以i节点为结尾的路径中,以'.' 为结尾的合法路径个数 。
转移方程见代码。
注意:本题有一个坑:所谓的以大写字母意思是去掉空格后,第一个字符为大写字符,不能有多个大写字母。
细节见代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d\n",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2) { ans = ans * a % MOD; } a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node {
int from;
int to;
char t;
node () {}
node(int ff, int tt, int ty)
{
from = ff;
to = tt;
t = ty;
}
};
int n, m;
std::vector<node> son[maxn];
queue<node> q;
node a[maxn];
int in[maxn];
ll dp[maxn][3];
const ll mod = (1ll << 32);
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
gbtb;
cin >> n >> m;
int u, v;
char t;
repd(i, 1, m) {
cin >> u >> v >> t;
son[u].pb(node(u, v, t));
in[v]++;
}
repd(i, 1, n) {
if (!in[i]) {
q.push(node(0, i, '_'));
}
}
int cnt = 0;
node temp;
while (!q.empty()) {
temp = q.front();
q.pop();
for (auto x : son[temp.to]) {
a[++cnt] = x;
in[x.to]--;
if (!in[x.to]) {
q.push(x);
}
}
}
repd(i, 1, cnt) {
if (a[i].t == '_') {
dp[a[i].to][0] += dp[a[i].from][0] + 1;
dp[a[i].to][1] += dp[a[i].from][1];
dp[a[i].to][2] += dp[a[i].from][2];
}
if (a[i].t == '.') {
dp[a[i].to][2] += dp[a[i].from][1];
}
if (a[i].t <= 'Z' && a[i].t >= 'A') {
dp[a[i].to][1] += dp[a[i].from][0] + 1;
}
if (a[i].t <= 'z' && a[i].t >= 'a') {
dp[a[i].to][1] += dp[a[i].from][1];
}
repd(j, 0, 2) {
dp[a[i].to][j] %= mod;
}
}
ll ans = 0ll;
repd(i, 1, n) {
ans = (ans + dp[i][2]) % mod;
}
cout << ans << endl;
return 0;
}
inline void getInt(int *p)
{
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
} else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}
Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )的更多相关文章
- Wannafly挑战赛2 D.Delete(拓扑排序 + dij预处理 + 线段树维护最小值)
题目链接 D.Delete 考虑到原图是个DAG,于是我们可以求出每个点的拓扑序. 然后预处理出起点到每个点的最短路$ds[u]$, 和所有边反向之后从终点出发到每个点的最短路$dt[u]$. 令点 ...
- Wannafly挑战赛22游记
Wannafly挑战赛22游记 幸运的人都是相似的,不幸的人各有各的不幸. --题记 A-计数器 题目大意: 有一个计数器,计数器的初始值为\(0\),每次操作你可以把计数器的值加上\(a_1,a_2 ...
- [NOIP2017]逛公园 最短路+拓扑排序+dp
题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...
- 洛谷P3244 落忆枫音 [HNOI2015] 拓扑排序+dp
正解:拓扑排序+dp 解题报告: 传送门 我好暴躁昂,,,怎么感觉HNOI每年总有那么几道题题面巨长啊,,,语文不好真是太心痛辣QAQ 所以还是要简述一下题意,,,就是说,本来是有一个DAG,然后后来 ...
- 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP
[BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...
- bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)
Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...
- 【bzoj4011】[HNOI2015]落忆枫音 容斥原理+拓扑排序+dp
题目描述 给你一张 $n$ 个点 $m$ 条边的DAG,$1$ 号节点没有入边.再向这个DAG中加入边 $x\to y$ ,求形成的新图中以 $1$ 为根的外向树形图数目模 $10^9+7$ . 输入 ...
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP
BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP Description In an effort to better manage t ...
随机推荐
- Android之View的绘制流程
本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定实现细 ...
- 多变量线性回归时使用梯度下降(Gradient Descent)求最小值的注意事项
梯度下降是回归问题中求cost function最小值的有效方法,对大数据量的训练集而言,其效果要 好于非迭代的normal equation方法. 在将其用于多变量回归时,有两个问题要注意,否则会导 ...
- 子系统 安装vsftpd
1.安装命令 sudo apt install vsftpd 2.为FTP添加用户,使用sudo useradd -m sunftp命令添加一个sunftp的用户 3. 授权文件夹 chmod 77 ...
- Jmeter之乱码 (一)
Jmeter历史版本下载: http://archive.apache.org/dist/jmeter/binaries/ Jmeter3.0接口测试脚本POST请求主体中的中文无法正确显示,现象如下 ...
- CentOS 7 卸载 mysql
查看是否安装 mysql rpm -qa | grep -i mysql yum list install mysql* 卸载 yum方式 yum remove mysql mysql-server ...
- 从“int中提取高八位”开始的学习
今天有个学弟问了一个问题,怎么提取int中的高八位. 这个是个非常基础的问题,随便用位运算瞎搞几下就出来了. 看到这个问题的时候,也不知道我当初想了些啥,想了个骚操作,用memcpy把int放到字符串 ...
- GitHub高级搜索
GitHub是开发目前最为活跃的开源网站和代码托管地,虽然我们经常使用GitHub,关注各种开源项目,但可能有很多人并不太了解GitHub的搜索功能的使用.GitHub提供了简单搜索和高级搜索,高级 ...
- 【Qt开发】QSplitter的使用和设置
Qt库版本:5.2.1 Qt Creator版本:3.0.1 1 QSplitter的用途 QSplitter使得用户可以通过拖动子窗口之间的边界来控制它们的大小,例如 图1 窗口拆分示意图 ...
- Maven从入门到精通(四)
这一篇我会着重讲解Maven的核心命令及作用,Maven在项目构建各个阶段的作用. 1.maven生命周期模型: 1.1.清洁(clean) 1.2.默认(default) 1.3.站点(site) ...
- Oracle恢复ORA-00600: 内部错误代码, 参数: [kcratr_scan_lastbwr] 问题的简单解决
Oracle恢复ORA-00600: 内部错误代码, 参数: [kcratr_scan_lastbwr] 1. 简单处理 sqlplus / as sysdba startup mount recov ...