codeforces 919 D Substring

本文介绍了一种寻找图中路径最大值的算法,通过遍历图的有向边,利用动态规划思想,寻找路径上字母出现的最大次数。文章详细解释了算法思路、环的检测方法及如何高效求解。

Description

You are given a graph with n nodes and m directed edges. One lowercase letter is assigned to each node. We define a path’s value as the number of the most frequently occurring letter. For example, if letters on a path are “abaca”, then the value of that path is 3. Your task is find a path whose value is the largest.

Input

The first line contains two positive integers n, m (1 ≤ n, m ≤ 300 000), denoting that the graph has n nodes and m directed edges.

The second line contains a string s with only lowercase English letters. The i-th character is the letter assigned to the i-th node.

Then m lines follow. Each line contains two integers x, y (1 ≤ x, y ≤ n), describing a directed edge from x to y. Note that x can be equal to y and there can be multiple edges between x and y. Also the graph can be not connected.

Output

Output a single line with a single integer denoting the largest value. If the value can be arbitrarily large, output -1 instead.

Examples

Input
5 4
abaca
1 2
1 3
3 4
4 5
Output
3
Input
6 6
xzyabc
1 2
3 1
2 3
5 4
4 3
6 4
Output
-1
Input
10 14
xzyzyzyzqx
1 2
2 4
3 5
4 5
2 6
6 8
6 5
2 10
3 9
10 9
4 6
1 10
2 8
3 7
Output
4

Note

In the first sample, the path with largest value is 13451 → 3 → 4 → 5. The value is 3 because the letter ‘a’ appears 3 times.


题意:给一个含n个结点和m条有向边的图。其中每一个结点都有一个小写字母与其对应。定义在一条路径上出现各个字母的最大次数为这条路径的value,求所有路径中最大的value。如果value是无限大,则输出-1。
思路:因为是最大value,同一条路径上,长的路径的value一定不小于短的路径,所以每条路径遍历到末尾就一定能找到该路径的最大value。

  • 输入的处理:对于m条边 xiyixi→yiyiyi一定不是路径的起点,把rt[yi]i]设为false
  • 因为是图,而且题目暗示了环的存在(value无限大的情况),所以把图遍历一遍。检查环的函数很容易实现,我是采用中序遍历,即访问一个结点之前,先访问他的所有子节点。有一个技巧就是在访问子节点的过程中,保持最开始的那个点的vis为-1,如果从它开始走了一圈又遇到了他,那么就会遇到这个-1。如果走完了整颗子树都没有遇到他,说明包含他以及他的子树都没有环,可以设为1,下一次就不用遍历了。
  • 答案的求解,也采用中序遍历,用dp[][]二维数组辅助存储,给每一个结点分配一个大小为[30]的数组 。中序遍历保证在统计每个结点时,他的子树的全部信息已经被记录到子节点中,在此基础上加入动态规划的思想,以字母a为例说明:
    • 转移方程:从结点出发的所有路径的最大value=结点含a的数量(0或1)+max{从第ii个子结点出发的所有路径中a的最大数量}
      • 在不断向上更新的过程中,每个结点都记录着从自己出发的路径中a的最大次数,也就是相当于只保存了含a最多的那条路径
      • 把各个子结点比较,也就是在选择各个子节点记录的路径
      • 每次都选含a最多的路径,那么最后起点保存的一定是含a做多的路径
    • 其他字母的处理方式也是一样的,所以可以放在一个循环里面,一次遍历把26个字母的信息同时更新以提高效率
#include<stdio.h>
#include<vector>//存储图和树比较方便的容器
#include<string.h>//为了使用memset()
#include<stdlib.h>//为了使用exit()
using std::vector;

#define c2n(ch) (ch-'a')//一个把a~z 映射到0~25的宏,便于用数组记录
#define max(a,b) ((a)>(b)?(a):(b))//比较大小的宏

const int maxn = 300005;
int n, m, a, b;

bool rt[maxn];//为了统计哪些结点是路径的起点
int dp[maxn][30];//动态规划的辅助数组

char lst[maxn];//记录每个结点对应的字母

vector<int>node[maxn];

int vis[maxn] = { 0 };//检查环的辅助数组

void solve(int num) {
    vis[num] = true;
    int next,l=node[num].size();
    for (int sn = 0; sn < l; ++sn)
    {//先序遍历,先处理所有儿子
        next = node[num][sn];
        if (vis[next] == false)
        solve(next);
    }
    //运行到这里说明所有儿子结点已经处理完毕(或者是叶子结点)
    for (int i = 0; i < 26; ++i) {//对于每个字母分别计数
        for (int sn = 0; sn < l; ++sn)//如果是叶子结点l=0,就没有这一步
        {//比较所有儿子的记录,选择最大的那一个
            dp[num][i] = max(dp[num][i], dp[node[num][sn]][i]);
        }
    }
    //在子节点中为各个字母选择最佳的路线后 
    //因为是从它出发,它所含字母的那条路线还应该+1
    dp[num][c2n(lst[num])]++;

}


int next;
void findring(int num) {//检查有无环的存在

    vis[num] = -1;
    int l = node[num].size();
    for (int i = 0; i < l; ++i) {
        next = node[num][i];
        if (vis[next] == 0)
            findring(next);
            else if (vis[next] == -1)
            {
                printf("-1");//遇到环可以直接输出-1然后结束程序
                exit(0);
            }
    }
    vis[num] = 1;//该结点的状态更新为从他开始往下不会有环
}

int main() {

    scanf("%d %d", &n, &m);
    //scanf("%s", lst);
    for (int i = 1; i <= n; ++i)
        while (1) { 
        scanf("%c", &lst[i]);  
        if ('a' <= lst[i] && 'z' >= lst[i]) 
        break;  
        }

    memset(rt, 1, sizeof rt);
    for (int i = 0; i < m; ++i) {
        scanf("%d %d", &a, &b);
        node[a].push_back(b);
        rt[b] = false;//b一定不是起点
    }

    memset(vis, 0, sizeof vis);
    for (int i = 1; i <= n; ++i) {
        if (vis[i] == false)
            findring(i);
    }

    memset(vis, 0, sizeof vis);
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        if (rt[i])//所有起点都要考虑一下
            solve(i);
    }
    for (int i = 1; i <= n; ++i)
        if (rt[i])//比较所有起点的,选最大的
            for (int k = 0; k < 26; ++k)
                if (ans < dp[i][k])
                    ans = dp[i][k];
    printf("%d", ans);
}
### Codeforces 1487D Problem Solution The problem described involves determining the maximum amount of a product that can be created from given quantities of ingredients under an idealized production process. For this specific case on Codeforces with problem number 1487D, while direct details about this exact question are not provided here, similar problems often involve resource allocation or limiting reagent type calculations. For instance, when faced with such constraints-based questions where multiple resources contribute to producing one unit of output but at different ratios, finding the bottleneck becomes crucial. In another context related to crafting items using various materials, it was determined that the formula `min(a[0],a[1],a[2]/2,a[3]/7,a[4]/4)` could represent how these limits interact[^1]. However, applying this directly without knowing specifics like what each array element represents in relation to the actual requirements for creating "philosophical stones" as mentioned would require adjustments based upon the precise conditions outlined within 1487D itself. To solve or discuss solutions effectively regarding Codeforces' challenge numbered 1487D: - Carefully read through all aspects presented by the contest organizers. - Identify which ingredient or component acts as the primary constraint towards achieving full capacity utilization. - Implement logic reflecting those relationships accurately; typically involving loops, conditionals, and possibly dynamic programming depending on complexity level required beyond simple minimum value determination across adjusted inputs. ```cpp #include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<long long> a(n); for(int i=0;i<n;++i){ cin>>a[i]; } // Assuming indices correspond appropriately per problem statement's ratio requirement cout << min({a[0], a[1], a[2]/2LL, a[3]/7LL, a[4]/4LL}) << endl; } ``` --related questions-- 1. How does identifying bottlenecks help optimize algorithms solving constrained optimization problems? 2. What strategies should contestants adopt when translating mathematical formulas into code during competitive coding events? 3. Can you explain why understanding input-output relations is critical before implementing any algorithmic approach? 4. In what ways do prefix-suffix-middle frameworks enhance model training efficiency outside of just tokenization improvements? 5. Why might adjusting sample proportions specifically benefit models designed for tasks requiring both strong linguistic comprehension alongside logical reasoning skills?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值