【Codeforces Round #460 (Div. 2) D】Substring
【链接】 我是链接,点我呀:)
【题意】
【题解】
如果有环 ->直接输出-1 (拓扑排序如果存在某个点没有入过队列,说明有环->即入队的节点个数不等于n否则。
说明可以做拓扑排序。
->是一个有向无环图。
那么定义f[x][y]
表示x节点前面的某条路径中,字母y出现的最多次数是多少次。
在拓扑排序的时候做DP就好。
(可以百度:有向无环图 DP 应该有挺多类似的题的
从入度为0的点开始进行DP。
然后遇到分叉的时候也没关系
取两条路中对应字母的较大值就好。
所以最后f[x][y]中不同字母的最大值可能就是不同的路径了。
(是哪一条不好说
然后显然你尽可能地多走一点路总是没错的。
(走过的点越多,字母出现的频率越高。
所以肯定是从一个端点到达另外一个端点。
(即从入度为0的端点开始走.
【代码】
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
const int N = 3e5;
int n,m,k,flag[N+10],now,dp[N+10][30];
char s[N+10];
vector<int> g[N+10];
int ru[N+10],a[N+10];
queue<int> dl;
int main(){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for (int i = 1;i <= m;i++){
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
ru[y]++;
}
for (int i = 1;i <= n;i++){
a[i] = s[i]-'a';
if (ru[i]==0){
dp[i][a[i]]++;
}
}
int num = 0;
for (int i = 1;i <= n;i++)
if (ru[i]==0){
num++;
dl.push(i);
}
while (!dl.empty()){
int x = dl.front();
dl.pop();
for (int y:g[x]){
if (ru[y]<=0) continue;
for (int i = 0;i < 26; i++){
dp[y][i] = max(dp[y][i],dp[x][i] + (a[y]==i) );
}
ru[y]--;
if (ru[y]==0){
num++;
dl.push(y);
}
}
}
if (num!=n){
puts("-1");
return 0;
}
int ma = 0;
for (int i = 1;i <= n;i++){
for (int j = 0;j < 26;j++){
ma = max(ma,dp[i][j]);
}
}
printf("%d\n",ma);
return 0;
}