1. 程式人生 > 實用技巧 >CodeForces-919D Substring DP,拓撲排序

CodeForces-919D Substring DP,拓撲排序

給定一個有n個節點和m條有向邊的圖。每個節點上有一個小寫字母。

我們將路徑的值定義為最經常出現的字母的數目。例如,如果路徑上的字母是“abaca”,那麼該路徑的值是3

你的任務是找到一條值最大的路徑,並將這條路徑的值輸出。

顯然條件是必須在一條路徑上,容易想到限制要求拓撲排序,因此可以在拓撲序上DP

dp[i][j]表示前i個點中,字母j出現的次數。

int n, m, u, v;
int num;
queue<int> q;
int dp[300005][27];
int Indeg[300005];
char s[300005];
vector<int> vec[300005
]; bool topo() { while (!q.empty()) q.pop(); num = 0; for (int i = 1; i <= n; i++) if (!Indeg[i]) { q.push(i); dp[i][s[i] - 'a']++; } while (!q.empty()) { int now = q.front(); q.pop(); num++; for (int i = 0; i < vec[now].size(); i++) {
if (--Indeg[vec[now][i]] == 0) { q.push(vec[now][i]); } for (int j = 0; j < 26; j++) { dp[vec[now][i]][j] = max(dp[vec[now][i]][j], dp[now][j] + (s[vec[now][i]] - 'a' == j)); } } } if (n == num) return true; else
return false; } int main() { n = readint(); m = readint(); scanf("%s", s + 1); for (int i = 0; i < m; i++) { int x = readint(); int y = readint(); vec[x].push_back(y); Indeg[y]++; } if (!topo()) puts("-1"); else { int Max = -1; for (int i = 1; i <= n; i++) { for (int j = 0; j < 26; j++) { Max = max(Max, dp[i][j]); } } Put(Max); } }