Codeforces Round #460 (Div. 2)_D. Substring_[dp][拓扑排序]

题意:一个有向图,每个结点 被赋予一个小写字母,一条路径的value等与这条路径上出现次数最多的字母的数目,求该图的最大value

比赛时,用dfs超时,看官方题解用的dp和拓扑排序,a--z用0-25表示,用dp[i][j]表示以第i个结点结尾的路径上第j个字母出现的次数

拓扑排序每排到一个点,就用该点的dp去更新与它相邻点的dp,最开始入度为0的点特殊处理了一下,dp过程中同步更新结果res

也复习了一下拓扑排序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define Nnum 300005

char ch[Nnum];
int dp[Nnum][26];

vector<int> eage[Nnum];
int deg[Nnum];
int n,m,res;
bool deg0[Nnum];

bool toposort()
{
    int cnt=0;
    queue<int> que;
    for(int i=1; i<=n; i++)
        if(deg[i]==0)
        {
            cnt++;
            que.push(i);
            deg0[i]=1;
        }
        else
            deg0[i]=0;
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        if(deg0[now]==1) //最初入度为0的点,其dp需附上初值,再更新相邻结点
            dp[now][ch[now-1]-‘a‘]++;
        for(int i=0; i<eage[now].size(); i++)
        {
            for(int j=0; j<26; j++)
            {
                int tmp=ch[eage[now][i]-1]-‘a‘;
                if(j==tmp)
                    dp[eage[now][i]][tmp]=max(dp[eage[now][i]][tmp],dp[now][tmp]+1);
                else
                    dp[eage[now][i]][j]=max(dp[eage[now][i]][j],dp[now][j]);
                res=max(res,dp[eage[now][i]][j]);
            }
            //cout<<"*"<<res<<endl;
            deg[eage[now][i]]--;
            if(deg[eage[now][i]]==0)
            {
                que.push(eage[now][i]);
                cnt++;
            }
        }
    }
    if(cnt==n)
        return 1;
    else
        return 0;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=n;i++)
            eage[i].clear();
        res=0;
        memset(deg,0,sizeof(deg));
        memset(dp,0,sizeof(dp));
        scanf("%s",ch);
        for(int i=0; i<m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            deg[b]++;
            eage[a].push_back(b);
        }
        if(toposort())
            printf("%d\n",res);
        else
            printf("-1\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/jasonlixuetao/p/8406072.html

时间: 2024-10-14 00:36:38

Codeforces Round #460 (Div. 2)_D. Substring_[dp][拓扑排序]的相关文章

Codeforces Round #460 (Div. 2)

A 签到 B 题意 定义:一个数(没有前缀0)的各个位数之和为10位"perfec"数,问第k个"perfect"数位多少(1<=k<=1e5) 分析 一开始找错了,以为会超过1e9,通过理性的分析不难发现,最大不超过1e9,强行打个表即可 C 签到 D 题意 n个点m条边的有向图,每个点有一个数字(可以重复,0~25),定义一条路径的权值为该路径出现数字最多的数字的次数,若有环输出-1,否则输出最大值 分析 思路:首先直接dfs肯定不行,最坏情况n^2

Codeforces Round #460 (Div. 2) B Perfect Number(二分+数位dp)

题目传送门 B. Perfect Number time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output We consider a positive integer perfect, if and only if the sum of its digits is exactly 1010. Given a positive integ

Codeforces Round #139 (Div. 2)C Barcode DP

#include<iostream> #include<cstdio> #include<cstring> using namespace std ; const int maxn = 1010; const int inf = 0x3f3f3f3f ; int dp[maxn][2] ; char str[maxn][maxn] ; int num[maxn]; int sum_b[maxn]; int sum_w[maxn]; int main() { // fre

Codeforces Round #276 (Div. 1)D.Kindergarten DP贪心

D. Kindergarten In a kindergarten, the children are being divided into groups. The teacher put the children in a line and associated each child with his or her integer charisma value. Each child should go to exactly one group. Each group should be a

Codeforces Round #271 (Div. 2) D.Flowers DP

D. Flowers We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all know, Marmot eats flowers. At every dinner he eats some red and white flowers. Therefore a dinner can be represented as a sequence of several

Codeforces Round #105 (Div. 2) D 概率DP

题目 呃 琢磨了半天还是琢磨出来了,题意有些模糊哈,有w个白色物品,b个黑色物品,A,B轮着抽,A先开始,谁先抽到白色谁赢,若最终都没有抽到白色 则算B赢,抽出来的物品不会放回去,B抽完以后 物品还会有一个额外产生丢失,问A赢的概率为多少 依旧是以目标状态为边界,当前状态到目标状态所需要的概率为 方程 dp[i][j] 代表当前轮到A抽的时候,还有i个白色的j个黑色的A赢的概率为多少 则当前转移可能有四种 1:A抽到了白色的,那么直接赢了,接下来不需要继续,所以没有与其它状态方程有联系 2:A抽

Codeforces Round #387 (Div. 2) 747F(数位DP)

题目大意 给出整数k和t,需要产生一个满足以下要求的第k个十六进制数 即十六进制数每一位上的数出现的次数不超过t 首先我们先这样考虑,如果给你了0~f每个数字可以使用的次数num[i],如何求长度为L且满足要求的十六进制数有多少个 dp[i][l]表示使用了前i个数字,已经将L的空位填上了l个的数有多少个 转移方程 dp[i][l] = sigma(dp[i-1][l-j]*C[len-l+j[j]) 其中j是枚举填新的数的个数,C是组合数(选出j个空位填上新数) 有了这个dp后,现在的问题就变

Codeforces Round #157 (Div. 1)B 数位dp

//枚举有几个(7或4),用数位dp的记忆化搜索找有i个(7或4)的数又多少个 //暴力搜索在第i个中选几个 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int mod = 1e9 + 7; int dp[20][20];//第i位有 j个数(7或者4) int bit[20] ; int temp[20]; int luck[20]; int dfs

Codeforces Round #168 (Div. 1)B 树形dp

//给一棵树,每次操作可以将包括顶点1的连通子集的所有点的节点加1或减1 //问最少几次操作使得这棵树的所有顶点的值都为0 //以1为根节点建树 //将加和减分开考虑,用up[u],down[u]表示以u为跟节点的子树中需要加的操作 //最大为up[u] ,需要减的操作最大为down[u] //其余的加和减的操作则可以在处理这两个操作时一起覆盖 //在将u的子数全都处理完后u点的值由于在加了up[u]和减了down[u]后变为 //一个新的值,则对于这个新的值根据它的正负并入up[u]或down