P6286

P6286 Cezar 题解


题意

求一个密钥,使加密后的单词按给定顺序排列。

转化

不妨设密钥为 \(k_i\),其中 \(i \in [1,26]\)

\(k_i\),表示字母 \(i\) 要替换为字母 \(k_i\)

转化一下,密钥就等于,钦定字母 \(i\) 是字典中的第 \(k_i\) 大(重定义字典序)。然后就不用考虑替换了。

问题等价于,问一个新的字母大小顺序,使得 \(n\) 个单词按给定顺序排列。

实现

这个很好做,图论建模。设给定顺序为 \(Order_i\),只要保证 \(\forall i \in [1,n)\)\(s_i < s_{i + 1}\) 即可。

\(s_i\) 是单词,\(<\)新字典序下的字符串比较。

那么我们就有了 \(n - 1\) 组形如 \(s_i < s_j\) 的字符串关系。

对于每组关系,找到最小的 \(k\) 使得 \(s_{i_k} \neq s_{j_k}\)。若存在,那么字母 \(s_{i_k}\) 的字典序小于 \(s_{j_k}\),在图中加有向边。

若不存在,分类讨论:

  • \(s_i\)\(s_j\) 前缀,根据字典序的定义,大小关系成立。

  • \(s_j\)\(s_i\) 前缀,根据字典序定义,恒不成立,输出无解。

然后要满足这些字母大小关系,拓扑即可。

最后,拓扑完之后入度数组没有清零的话,就存在环,输出无解。

设字符串长度为 \(L\),时间复杂度 \(O(n \times L + C)\),其中 \(C = 26\)

//Problem: P6286
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define i32 INT_MAX
#define i64 LONG_LONG_MAX
#define pii std::pair<int, int>
#define pll std::pair<long long, long long>
#define pb push_back
#define fore(i,u,v) for(int i=head[u],v;i;i=e[i].nxt)
typedef long long ll;
const int N = 105;
ll read(){ll x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}return x*f;}
void print(ll x){if(x<0)putchar('-'),x=-x;if(x>9)print(x/10);putchar(x%10+48);}
char gc(){char c=getchar();while(c==' '||c=='\n')c=getchar();return c;}
void pc(char Char){std::putchar(Char);}

int n, cnte, len;
int Order[N], Len[N], head[27], in[27], List[27], ans[27];
char a[N][N];

struct edge {
    int v, nxt;
} e[N];

std::queue <int> q;

void adde(int u, int v) {
    e[++cnte] = (edge){v, head[u]};
    head[u] = cnte;
    in[v]++;
}
void TopoSort() {
    for(int i = 1; i <= 26; i++) if(!in[i]) List[++len] = i, q.push(i);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        fore(i, u, v) {
            v = e[i].v;
            in[v]--;
            if(in[v] == 0) {
                List[++len] = v;
                q.push(v);
            } 
        }
    }
}

int main() {
    // freopen("P6286_3.in", "r", stdin);
    // freopen("out.out", "w", stdout);
    std::cin >> n;
    for(int i = 1; i <= n; i++) scanf(" %s", a[i] + 1), Len[i] = strlen(a[i] + 1);
    for(int i = 1; i <= n; i++) Order[i] = read();
    for(int i = 1; i < n; i++) {
        int Flag = 0;
        for(int k = 1; k <= Len[Order[i]] && k <= Len[Order[i + 1]]; k++) {
            if(a[Order[i]][k] != a[Order[i + 1]][k]) {
                adde(a[Order[i]][k] - 'a' + 1, a[Order[i + 1]][k] - 'a' + 1);
                // std::cout << a[Order[i]][k] << ' ' << a[Order[i + 1]][k] << '\n';
                Flag = 1;
                break;
            }
        }
        if(!Flag) {
            if(Len[Order[i]] > Len[Order[i + 1]]) {
                puts("NE");
                return 0;
            }
        }
    }
    TopoSort();
    for(int i = 1; i <= 26; i++) {
        if(in[i] != 0) {
            puts("NE");
            return 0;
        }
        // std::cout << in[i] << '\n';
    }
    puts("DA");
    for(int i = 1; i <= 26; i++) ans[List[i]] = i;
    for(int i = 1; i <= 26; i++) {
        pc(ans[i] + 'a' - 1);
    }
    return 0;
}
posted @ 2024-01-11 10:17  CWzwz  阅读(5)  评论(0编辑  收藏  举报