一 原题
D. Substring
You are given a graph with n nodes and m directed edges. One lowercase letter is assigned to each node. We define a path's value as the number of the most frequently occurring letter. For example, if letters on a path are "abaca", then the value of that path is 3. Your task is find a path whose value is the largest.
The first line contains two positive integers n, m (1 ≤ n, m ≤ 300 000), denoting that the graph has n nodes and m directed edges.
The second line contains a string s with only lowercase English letters. The i-th character is the letter assigned to the i-th node.
Then m lines follow. Each line contains two integers x, y (1 ≤ x, y ≤ n), describing a directed edge from x to y. Note that x can be equal to y and there can be multiple edges between x and y. Also the graph can be not connected.
Output a single line with a single integer denoting the largest value. If the value can be arbitrarily large, output -1 instead.
5 4 abaca 1 2 1 3 3 4 4 5
3
6 6 xzyabc 1 2 3 1 2 3 5 4 4 3 6 4
-1
10 14 xzyzyzyzqx 1 2 2 4 3 5 4 5 2 6 6 8 6 5 2 10 3 9 10 9 4 6 1 10 2 8 3 7
4
In the first sample, the path with largest value is 1 → 3 → 4 → 5. The value is 3 because the letter 'a' appears 3 times.
二 分析
DFS判断是否有环,如果有环,那么输出-1。如果没有环,那么DFS后得到原图的一个拓扑排序,对于任意一条图上的路径(v1->v2->v3...),在拓扑排序中保证v_i在v_i+1之前,那么我们就可以动归得到每个点作为起点时,某个字母最多出现多少次。下面两份代码,一份是DFS,一份是裸的拓扑排序。复杂度:O(26*(n+m))
三 代码
/*
PROB: cf 919D
LANG: c++
AUTHOR: maxkibble
*/
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
// #define local
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
const int maxn = 3e5 + 10;
int n, m, s, e, ans = 1, dp[maxn];
char ch[maxn];
bool in[maxn], vis[maxn];
vector<int> edge[maxn], seq;
bool circle(int x) {
bool ret = false;
in[x] = vis[x] = true;
for(auto nxt: edge[x]) {
if(in[nxt]) {
ret = true;
break;
}
if(!vis[nxt] && circle(nxt)) {
ret = true;
break;
}
}
in[x] = false;
seq.pb(x);
return ret;
}
int main() {
#ifdef local
freopen("d.in", "r", stdin);
#endif
scanf("%d%d%s", &n, &m, ch + 1);
for(int i = 0; i < m; i++) {
scanf("%d%d", &s, &e);
edge[s].pb(e);
}
for(int i = 1; i <= n; i++) {
if(vis[i]) continue;
if(circle(i)) {
puts("-1");
return 0;
}
}
for(char c = 'a'; c <= 'z'; c++) {
for(int i = 0; i < seq.size(); i++) {
int v = seq[i];
int flag = (ch[v] == c);
dp[v] = flag;
for(auto nxt: edge[v]) {
dp[v] = max(dp[v], dp[nxt] + flag);
}
ans = max(ans, dp[v]);
}
}
printf("%d\n", ans);
return 0;
}
/*
PROB: cf 919D
LANG: c++
AUTHOR: maxkibble
*/
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
// #define local
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
const int maxn = 3e5 + 10;
int n, m, s, e, ans = 1, degree[maxn], dp[maxn];
char ch[maxn];
queue<int> q;
vector<int> edge[maxn], seq;
void topSort() {
for(int i = 1; i <= n; i++) {
for(auto nxt: edge[i])
degree[nxt]++;
}
for(int i = 1; i <= n; i++) {
if(degree[i] == 0)
q.push(i);
}
while(!q.empty()) {
int u = q.front();
seq.pb(u);
q.pop();
for(auto v: edge[u]) {
degree[v]--;
if(degree[v] == 0)
q.push(v);
}
}
}
int main() {
#ifdef local
freopen("d.in", "r", stdin);
#endif
scanf("%d%d%s", &n, &m, ch + 1);
for(int i = 0; i < m; i++) {
scanf("%d%d", &s, &e);
edge[s].pb(e);
}
topSort();
if(seq.size() != n) {
puts("-1");
return 0;
}
for(char c = 'a'; c <= 'z'; c++) {
for(int i = n - 1; i >= 0; i--) {
int v = seq[i];
int flag = (ch[v] == c);
dp[v] = flag;
for(auto nxt: edge[v]) {
dp[v] = max(dp[v], dp[nxt] + flag);
}
ans = max(ans, dp[v]);
}
}
printf("%d\n", ans);
return 0;
}