Codeforces #445 Div2 D

#445 Div2 D

题意

给出一些字符串,要求构造一个最短的且字典序最小的字符串,使得给出的字符串都为目标字符串的子串,且这些字符串作为子串出现的次数都是最多的,如果不存在目标字符串输出 "NO"。

分析

显然,每个字符只能出现一次。
然后,一个长度为 \(l\) 的字符串,其实指明了 \(l-1\) 个连边关系,如字符串 ab ,那么 \(a\) 的后面一定只能为 \(b\) 所以 \(a\) \(b\) 连有向边,且只能有一条边连向 \(b\)\(a\) 只能连一条边出去。这个想法确立了,后面就好做了。

code

#include<bits/stdc++.h>
using namespace std;
int nxt[130], vis[130], f[130];
char s[111111];
int main() {
    int n;
    cin >> n;
    int flg = 1;
    memset(nxt, -1, sizeof nxt);
    for(int i = 0; i < n; i++) {
        scanf("%s", s);
        if(f[s[0]] != -1) f[s[0]] = 1;
        vis[s[0]] = 1;
        int len = strlen(s);
        for(int j = 1; j < len; j++) {
            int c = s[j];
            int &x = nxt[s[j - 1]];
            f[c] = -1;
            if(x == -1) x = c;
            else if(x != c) flg = 0;
            vis[c] = 1;
        }
    }
    if(!flg) cout << "NO" << endl;
    else {
        int cnt = 0;
        for(int i = 'a'; i <= 'z'; i++) {
            if(vis[i] && f[i] == 1) {
                int t = i;
                while(t != -1) {
                    vis[t] = 0;
                    s[cnt++] = t;
                    t = nxt[t];
                    if(t != -1 && vis[t] == 0) {
                        flg = 0;
                        break;
                    }
                }
            }
        }
        for(int i = 'a'; i <= 'z'; i++) {
            if(vis[i]) flg = 0;
        }
        s[cnt] = 0;
        if(!flg) cout << "NO" << endl;
        else cout << s << endl;
    }
    return 0;
}
posted @ 2017-11-13 13:26  ftae  阅读(234)  评论(0编辑  收藏  举报