博客
关于我
【DG特长生2019 T4】【SSL 2892】文档恢复
阅读量:324 次
发布时间:2019-03-04

本文共 3399 字,大约阅读时间需要 11 分钟。

文档恢复

题目链接:

题目大意

有一个规则,原来的字母会变成规定的另一种,不会有两个字母变成相同的字母。

然后按顺序给出按原来的字典序排好的字符串,然后再给你一个字符串,要你还原出边之前的。
如果无解或者有多组解就输出 0。

思路

大概就是先通过给出的字典序进行判断,求出两个字符之间的字典序大小关系。

(记得如果矛盾就直接是 0)

然后你就大概想拓扑一样,每次找比其他所有字符都大的点。

(具体就是在你求出的大小关系中,它一定会至少大于一个点,且一定不会小于任何点)

然后每次这个点只能有一个,否则就会有多组解。(其实就是一个找链的过程)

然后你每次找到就给他记录它是字典序第几大的,然后把这个点删掉。

最后你就读入要翻译的字符串,然后按你记录的转,再输出就可以了。

记得出现的字母不一定是从 a 开始顺着下来的,所以你还要记录一下字典序第 i 大变化前是哪个字符。

代码

#include
#include
using namespace std;int a, k, root = -1, ans[500001];int gx[31][31], dy[31], sn, mb[31];char c[500001][101], ac[500001];bool noans, cx[31];void work(int deg, int l, int r) { //得出关系 if (l == r || l > r) return ; if (noans) return ; if (!c[l][deg - 1]) return ; int last = l; for (int i = l + 1; i <= r; i++) if (c[i][deg] != c[last][deg]) { if (!c[last][deg]) { last = i; continue; } cx[c[last][deg] - 'a'] = 1; work(deg + 1, last, i - 1); if (!c[i][deg]) { last = i; continue; } cx[c[i][deg] - 'a'] = 1; if (gx[c[i][deg] - 'a'][c[last][deg] - 'a'] == 1) { //关系与之前矛盾 noans = 1; return ; } gx[c[i][deg] - 'a'][c[last][deg] - 'a'] = -1;//确立关系 gx[c[last][deg] - 'a'][c[i][deg] - 'a'] = 1; last = i; } work(deg + 1, last, r);//记得最后那一段}int main() { // freopen("resume.in", "r", stdin);// freopen("resume.out", "w", stdout); memset(dy, -1, sizeof(dy)); scanf("%d %d", &a, &k); for (int i = 1; i <= k; i++) scanf("%s", &c[i]); int last = 1;//同上,只是一开始处理大序列的 for (int i = 2; i <= k; i++) { if (c[i][0] != c[last][0]) { cx[c[i][0] - 'a'] = 1; cx[c[last][0] - 'a'] = 1; work(1, last, i - 1); if (noans) break; if (gx[c[i][0] - 'a'][c[last][0] - 'a'] == 1) { noans = 1; break; } gx[c[i][0] - 'a'][c[last][0] - 'a'] = -1; gx[c[last][0] - 'a'][c[i][0] - 'a'] = 1; last = i; } } work(1, last, k);//记得最后那一段 if (noans) { //产生了矛盾 printf("0"); return 0; } for (int i = 0; i < 26; i++)//记录按字典序排下来是那些字母 if (cx[i]) mb[++mb[0]] = i; for (int I = 1; I <= mb[0]; I++) { int i = mb[I]; bool yes = 1, have = 0; for (int j = 0; j < 26; j++) if (gx[i][j] == -1) { yes = 0; break; } else if (gx[i][j] == 1) { have = 1; } if (yes && have) { if (root != -1) { //有多组解(建图的话就是多个连通块) printf("0"); return 0; } root = i; } else if (yes && !have) { //多组解 printf("0"); return 0; } } if (root == -1) { //矛盾(图就是成了环) printf("0"); return 0; } dy[root] = 1; for (int i = 0; i < 26; i++)//取消掉这个点 gx[i][root] = gx[root][i] = 0; for (int I = 2; I < a; I++) { //刚刚的是确立字典序最小的,接着就是确立后面的 root = -1; for (int II = 1; II <= mb[0]; II++) { int i = mb[II]; if (dy[i] != -1) continue; bool yes = 1, have = 0; for (int j = 0; j < 26; j++) if (gx[i][j] == -1) { yes = 0; break; } else if (gx[i][j] == 1) { have = 1; } if (yes && have) { if (root != -1) { printf("0"); return 0; } root = i; } else if (yes && !have) { printf("0"); return 0; } } if (root == -1) { printf("0"); return 0; } dy[root] = I; for (int i = 0; i < 26; i++) gx[i][root] = gx[root][i] = 0; } for (int I = 1; I <= mb[0]; I++) { int i = mb[I]; if (dy[i] == -1) { dy[i] = a; break; } } scanf("%s", &ac);//读入,复原 sn = strlen(ac); for (int i = 0; i < sn; i++) ans[i] = dy[ac[i] - 'a']; for (int i = 0; i < sn; i++) putchar(mb[ans[i]] + 'a'); fclose(stdin); fclose(stdout); return 0;}

转载地址:http://mgvh.baihongyu.com/

你可能感兴趣的文章
vue中接收后台的图片验证码并显示
查看>>
趣谈win10常用快捷键
查看>>
王爽 《汇编语言》 读书笔记 三 寄存器(内存访问)
查看>>
IDEA出现问题:Received fatal alert: protocol_version 解决方案
查看>>
Airtest自动化测试 Docs airtest.core.android package
查看>>
JDK 内置的多线程协作工具类的使用场景
查看>>
Java 中哪些对象可以获取类对象
查看>>
11.2.6 时间值的小数秒
查看>>
Redis源码分析(七)--- zipmap压缩图
查看>>
自定义Hive Sql Job分析工具
查看>>
【MySQL】(九)触发器
查看>>
Oracle 11G环境配置
查看>>
【Python】(十二)IO 文件处理
查看>>
【Oozie】(三)Oozie 使用实战教学,带你快速上手!
查看>>
师兄面试遇到这条 SQL 数据分析题,差点含泪而归!
查看>>
C语言的数值溢出问题(上)
查看>>
函数指针的典型应用-计算函数的定积分(矩形法思想)
查看>>
8051单片机(STC89C52)以定时器中断模式实现两倒计时器异步计时
查看>>
用 wxPython 打印你的 App
查看>>
vue项目通过vue.config.js配置文件进行proxy反向代理跨域
查看>>