Codeforces 919D Substring (拓扑排序+树形dp)

题目:Substring

题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1。

题解:当这个有向图构成一个环的时候就会使得值无限大,所以先用拓扑排序判断一下有没有环,如果有环直接输出-1, 如果没有环就再使用树形dp并记忆化存数,来找到最大值。

代码:

 1 #include<cstring>
 2 #include<iostream>
 3 using namespace std;
 4 const int N = 300000+5;
 5 string str;
 6 int head[N], c[N], topo[N], dp[N][26];
 7 int cnt = 0, n, m, k, ans = 0;
 8 struct Node
 9 {
10     int nx;
11     int to;
12 }Edge[N];
13 void add_edge(int u, int v)
14 {
15     Edge[cnt].to = v;
16     Edge[cnt].nx = head[u];
17     head[u] = cnt++;
18 }
19 bool dfs(int u)
20 {
21     c[u] = -1;
22     for(int i = head[u]; ~i; i = Edge[i].nx)
23     {
24         int v = Edge[i].to;
25         if(c[v] < 0) return false;
26         else if(!c[v] && !dfs(v)) return false;
27     }
28     c[u] = 1;
29     topo[--k] = u;
30     return true;
31 }
32 bool topo_sort()
33 {
34     k = n;
35     memset(c, 0, sizeof(c));
36     for(int i = 0; i < n; i++)
37     {
38         if(!c[i])
39             if(!dfs(i)) return false;
40     }
41     return true;
42 }
43 void dfs_count(int u)
44 {
45     c[u] = 1;
46     for(int i = head[u]; ~i; i = Edge[i].nx)
47     {
48         int v = Edge[i].to;
49         if(!c[v]) dfs_count(v);
50         for(int i = 0; i < 26; i++)
51         {
52             if(dp[u][i] < dp[v][i])
53             {
54                 dp[u][i] = dp[v][i];
55                 int tmp  = (str[u]-‘a‘ == i)? dp[u][i]+1 : dp[u][i];
56                 if(tmp > ans) ans = tmp;
57             }
58         }
59     }
60     dp[u][str[u]-‘a‘]++;
61 }
62 int main()
63 {
64     ios::sync_with_stdio(false);
65     cin.tie(0);
66     memset(head, -1, sizeof(head));
67     cin >> n >> m;
68     cin >> str;
69     int u, v;
70     for(int i = 1; i <= m; i++)
71     {
72         cin >> u >> v;
73         add_edge(u-1, v-1);
74     }
75     if(!topo_sort())
76     {
77         cout << -1 << endl;
78         return 0;
79     }
80     memset(c, 0, sizeof(c));
81     for(int i = 0; i < n; i++)
82     {
83         if(!c[topo[i]])
84             dfs_count(topo[i]);
85     }
86     cout << ans << endl;
87 }

原文地址:https://www.cnblogs.com/MingSD/p/8400745.html

时间: 2024-08-28 06:37:07

Codeforces 919D Substring (拓扑排序+树形dp)的相关文章

【Luogu】P3116会议时间(拓扑排序,DP)

题目链接 本题使用拓扑排序来规划DP顺序.设s[i][j]表示i步是否能走到j这个点,e[i][j]表示i步是否能走到j这个点——用第二条路径.因为要满足无后效性和正确性,只有第i个点已经全部更新完毕的时候才能用它来更新其他的点.所以用拓扑. 代码如下 #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; inline long

CF-721C DAG图拓扑排序+费用DP

比赛的时候写了个记忆化搜索,超时了. 后来学习了一下,这种题目应该用拓扑排序+DP来做. dp[][]保存走到[第i个节点][走过j个点]时所用的最短时间. pre[][]用前驱节点求路径 然后遍历一下dp[n][],求满足t范围的最大下标. #include <iostream> #include <queue> #include <cstdio> #include <vector> #include <stack> #define N 505

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Codeforces 462D Appleman and Tree 树形dp

题目链接:点击打开链接 题意: 给定n个点的树, 0为根,下面n-1行表示每个点的父节点 最后一行n个数 表示每个点的颜色,0为白色,1为黑色. 把树分成若干个联通块使得每个联通块有且仅有一个黑点,问有多少种分法(结果mod1e9+7) 思路: 树形dp,每个点有2个状态,已经归属于某个黑点和未归属于某个黑点. #include <cstdio> #include <vector> #include <iostream> using namespace std; #de

Codeforces 543D Road Improvement(树形DP+乘法逆元)

题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和HDU2196是一种类型的树形DP,因为它们都要分别求各个点的答案.然后解法也不难想: dp0[u]表示只考虑以u结点为根的子树的方案数 dp1[u]表示u结点往上走,倒过来,以它父亲为根那部分的方案数 有了这两部分的结果,对于各个点u的答案就是dp0[u]*(dp1[u]+1).这两部分求法如下,画

Codeforces 627D Preorder Test(二分+树形DP)

题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值. 考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1. 考虑树形DP. 用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上. 那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的

Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)

E. Selling Souvenirs time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output After several latest reforms many tourists are planning to visit Berland, and Berland people understood that it's an op

CodeForces 55D Beautiful numbers (树形DP)

想了半天,总算想出来了.这题刚上来的思路很明显是11维DP..但是明显不可取.. 这题的关键在于只要两个数前面的拥有的数字是一样的,而且此时与其最小公倍数的模是一样的,那么这时候就可以认为对所有的数字取模都是相等的,那么后面的总情况数属于完美数的情况也是相同的. 只要想到这步的话,那么基本思路就出来了,我第一次居然脑残的记录lcm与模2520(2到9的最小公倍数),首先lcm相同并不代表出现的数字相同先不说,仅仅这个最大值就太大了,lcm最大是2520,这样的话就需要开一个20*2520*252

Codeforces 700B Connecting Universities(树形DP)

[题目链接] http://codeforces.com/problemset/problem/700/B [题目大意] 给出 一棵n个节点的树, 现在在这棵树上选取2*k个点,两两配对,使得其配对的两点间距离的和最大. [题解] 求出树的加权重心,那么答案就是每个点到加权重心的距离之和,但是实际上,并不需要求出加权重心,观察树边和其两边的询问节点,可以发现一个优美的性质,每条边对答案的贡献值为min(左边的点数,右边的点数),因此,树规计算每条边的贡献值,累加和就是答案. [代码] #incl