リンク:https://ac.nowcoder.com/acm/contest/160/B
出典:牛オフネットワーク
説明タイトル
を含む点にn及びmは(ポイントは1からnまでの整数を表すと、エッジを許可)有向非巡回グラフ縁、キャラクタの各エッジは、いくつかの経路は、図中、Q経路が満たしています。ストリップスペース大文字の後端からなる文字列の後に、完全に停止「」端、中間のすべて小文字、小文字は0であってもよいです。
入力説明:
二つの整数の最初のラインN、M
二つの整数、b及びキャラクタCの次のM個のラインは、始点A、終点B側、文字Cのエッジとして表さ
1≤。 N-、m個の≤50000
1 <N- B≤≤。
Cは、小文字、またはスペース期間であってもよい(「「との便宜のために」」スペースを表す)
出力の説明:
出力回答モジュロ232の結果を表す整数
例
入力された
コピー
。6. 11
1 2 A
1 2
3 4
2 4 B
2 3
2 3
2 4 B
。4. 5
。3 5
2 5
5 6 _
出力
コピー
16
アイデア:
まず、トポロジカル整列、
なぜトポロジカルそれをソートしますか?
我々はそれが有向グラフであることを知っているので、2つのノードがトポロジカルソート後には存在しない、ために、トポロジーbはaとbを以下の、aとbは、エッジ点があり、それが存在していないです。
プロセスDPの中で、私たちの国家の一つは、もはや変化があってはならない状態を必要と状態に応じて元から転送されているので。
これは、動的プログラミングのノー後の効果であります:
当前的值只和当前的状态有关,和之前怎么来到这个状态和之后怎么去其他状态都无关。
我々はトポロジカル再びソートした後は、文字クラスの状態側に転送する必要があります。
次のように我々は、DPの状態を定義します。
DP [i]は[0]:私は、パスの最後に、パス数はスペースのみを含むノード。
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';
}
}
}