牛客暑假第5场补题之H题

链接:https://ac.nowcoder.com/acm/contest/885/H
来源:牛客网

There is a hidden string of length n composed of the first m lowercase English letters. For any two different English letters, we will tell you a subsequence of the hidden string constructed by removing all other letters from the hidden string.

For example, if the hidden string is “apple” and the chosen letters are ‘e’ and ‘p’, the resulting subsequence would be “ppe”; if the chosen letters are ‘a’ and ‘x’, the resulting subsequence would be “a”.

Now, please recover the hidden string. Output -1 if there are no possible hidden string. Output any one if there are multiple possible hidden strings.

题意就是给你一个字符串 这个字符串长度为n 由前m个小写字母构成 这个串一开始是不知道的 然后给你m*(m -1 )/ 2种 输入 每种输入包含前m个字符 并且如果字符c在s串种出现的话 那么就按照c在s串种的顺序直接给出 ;

其实对于每个输入的字符的话 我们就可以看作每个相邻之间的有一条边 按照所给的字符串连边就好了 对于一个字符c 如果在s串种出现的话 我们直接给其一个编号为tot 后面再次连边的话就直接连接到tot上面就好了 对于相同字符的连接就是采取编号制
id[i][j] 表示第i个字符第j次出现时候的编号为多少 对于新加入进来的东西 如果id[i][j] == -1
那么就说明我这个字符其实是之前没有出现的 没有带编号的 那么就可以给这个字符编号一下 最后跑一下拓扑排序就好了 注意一开始给的节点个数可能是不为n个 注意特判一下每个字符是否出现 然后从没有出现的去补 把长度补到为n的长度就好了 就是一个拓扑排序的变种题 这种题目还是练习的少哎 补题补提 跑完topsort也要特判一下是否长度为n
因为topsort可能会有冲突存在
本文参考了 :https://blog.csdn.net/ltrbless/article/details/98171170

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 10;

int tot = 0; // 这个题目重要在给每一个节点加一个编号

int vis[30],used[30],id[30][maxn],mp2[30],in[maxn]; // 表示第i个字符第t次出现的标志值是多少
// g 里面添加的就是边
char isch[maxn];
vector<int> g[maxn];

int main()
{

    int n,m;
    char s[maxn];
    scanf("%d%d",&n,&m);
    memset(id,-1,sizeof id);
    m = m * (m - 1) / 2;
    while(m --)
    {
        int len;
        scanf("%s%d",s,&len);
        if(len) scanf("%s",s);
        else
        {
            getchar();continue;
        }
        for(int i = 0; i < len; i++)
        {
            int ch = s[i] - 'a';
            mp2[ch] = 1; // 标记一下这个字符出现过了
        }
        memset(vis,0,sizeof vis);
        memset(used,0,sizeof used);
        for(int i = 0; i < len; i++)
        {
            int t = s[i] - 'a';
            vis[t]++;
            //cout<<"tot :"<<tot<<endl;
            //printf("t = %d vis t = %d\n",t,vis[t]);
            if(id[t][vis[t]] == -1)
            {
                id[t][vis[t]] = tot++; // 给这个节点字符编一个号
                isch[tot - 1] = 'a' + t; // 存一下这节点的字符是什么
            }
            used[i] = id[t][vis[t]];
        }
        for(int i = 0; i < len - 1; i++)
        {
            g[used[i]].push_back(used[i + 1]); // creat
            in[used[i + 1]] ++;
        }
    }
    int last = 0;
    if(tot < n)// 所给的点小于n个
    {
        int f = 0,i;
        for(i = 0; i <= m - 1; i++)
        {
            if(mp2['a' + i] == 0)
            {
                f = 1;break;
            }
        }
        if(!f)
        {
            puts("-1");return 0;
        }
        else
        {
            int temp = n - tot;
            for(int j = 0; j < temp; j++)
            {
                isch[tot++] = 'a' + i;
            }
        }
    }
    queue<int> q;
    for(int i = 0; i < tot; i++)
    {
        if(in[i] == 0)
        {
            q.push(i);
        }
    }
    string ans = "";
    while(q.size())
    {
        int now = q.front();q.pop();
        ans += isch[now];
        for(int i = 0; i < g[now].size(); i++)
        {
            int u = g[now][i];
            in[u]--;
            if(in[u] == 0)
            {
                q.push(u);
            }
        }
    }
    if(ans.size() != n) puts("-1");
    else cout<<ans<<endl;
    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值