【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;
}
posted @ 2018-02-01 01:55  AWCXV  阅读(178)  评论(0编辑  收藏  举报