2019牛客多校第五场H

H - subsequence 2

题意

要你使用(m)个小写字母构造一个长度为(n)的字符串
(m*(m-1)/2)限制条件:

  • (c_{1} 、c_{2}、 len):表示除去其他非(c_{1}、c_{2})之外的字母剩下的串长度为(len)
  • (s):除去其他非(c_{1}、c_{2})之外的字母剩下的字符串,长度为(len)

需要我们根据这个限制条件构造出原串,如果不存在输出(-1)

思路

我们可以发现题目给了两个字母之间的相对位置。比如(aab),第二个(a)前面一定得接了个(a)(b)一定要第二个(a)的条件符合之后,然后第二个(a)放进去之后才能到(b)
那么对于每个字母都要先把前面的都输出完了,才能到自己,那么我们可以想到拓扑(其实是队友想的),一定要入度为零才能到本身,然后我们就可以和拓扑结合起来。

  • 定义字母:我们可以令(a)(0000)~(9999)之间的数来定义(因为最多可能有(1e^4)个), 然后(b)(10000)~(19999)这样接下去定义每个字母。
  • 建图:根据题目给的串建图, 前后建一条边。
  • 然后去跑拓扑就(OK)
  • 如果你构造出来的串长度不为(n)就输出(-1)(出现循环节之类乱七八糟的情况)

一些坑点

  • 建图的时候要判断会不会出现前面出现的(a)(3)个,这次出现的(a)(4)个这样的情况,这样不符合条件,可以加一个数组特判一下。
  • 输入要注意(len = 0)的时候会输入空行,这边要处理好。(没处理好的我,(WA)了好多发)

一些数据

这些数据都是输出(-1),其实我第一组数据之前只是输入出锅了,然后导致我一直(WA),其实我没有输出(-1)也过了

3 3
ab 3
aab
ac 2
aa
bc 0

3 3
ab 3
aab
ac 1
a
bc 1
b

AC 代码

(本人太菜,代码很乱,请多见谅)

#include<bits/stdc++.h>
#define mes(a, b) memset(a, b, sizeof a)
using namespace std;
const int maxn = 1e4+10;
int n, m;
int head[maxn*50], f[30], cnt, in[maxn*50], sum[30];
char ch[maxn];
vector<int>  ans;
struct Edge{
    int v, next;
}e[maxn*50];

void init(){    //初始化
    mes(head, -1);
    mes(in, 0);
    mes(sum, 0);
    for(int i = 0; i <= 26; i++){
        f[i] = i*10000;
    }
    ans.clear();
    cnt = 0;
}

void add(int u, int v){     
    e[++cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

int change(int u){     //根据字母的ID转换为字母
    for(int i = 0; i < 26; i++){
        if(u - f[i] < 10000)
            return i;
    }
}

int topu(){
    queue<int> q;
    int tot = 0;
    for(int i = 0; i < m; i++){
        for(int j = 0; j < sum[i]; j++){
            if(!in[j+f[i]]){
                q.push(j+f[i]);
            }
        }
    }
    while(!q.empty()){
          int u = q.front(); q.pop();
          if(change(u) >= m)
              return -1;
          ans.push_back(change(u));
          tot++;
          for(int i = head[u]; ~i; i = e[i].next){
              int v = e[i].v;
              in[v]--;
              if(!in[v])
                  q.push(v);
          }
    }
    return tot;
}

int main(){
    scanf("%d%d", &n, &m);
    init();
    int q = m*(m-1)/2;
    char c1, c2;
    int len;
    int flag = 0;
    while(q--){
        char s[10];
        scanf("%s%d", s, &len);
        c1 = s[0];c2 = s[1];
        getchar();
        gets(ch);
        int cnt1 = 0, cnt2 = 0, u, v;       //cnt1:c1字母出现的次数
        if(len > 0){                        //cnt2:c2字母出现的次数
            if(ch[0] == c1){
                u = cnt1+f[c1-'a'];
                cnt1++;     
            }
            else{
                u = cnt2+f[c2-'a'];
                cnt2++;
            }
            for(int i = 1; i < len; i++){
                if(ch[i] == c1){
                    v = cnt1+f[c1-'a'];
                    cnt1++;
                }
                else{
                    v = cnt2+f[c2-'a'];
                    cnt2++;
                }
                add(u, v);
                 u = v;
                in[v]++;
            }
        }
        if(!sum[c1-'a']|| sum[c1-'a'] == cnt1)  //如果这次出现的次数和之前不一样,不符合条件
            sum[c1-'a'] = cnt1;
        else
            flag = 1;
        if(!sum[c2-'a']|| sum[c2-'a'] == cnt2)
            sum[c2-'a'] = cnt2;
        else
            flag = 1;
    }
    int num = topu();
    if(num != n || flag){
        printf("-1
");
        return 0;
    }
    for(int i = 0; i < ans.size(); i++){
        printf("%c", ans[i]+'a');
    }
    printf("
");
    return 0;
}
原文地址:https://www.cnblogs.com/zhuyou/p/11285663.html