【hihoCoder 1466】后缀自动机六·重复旋律9
http://hihocoder.com/problemset/problem/1466
建出A串和B串的两个后缀自动机
对后缀自动机的每个状态求出sg值。
求出B串的\(sum(x)\),表示B有多少子串的sg值等于x(用拓扑序求)。
对A串的每个状态,求出B串有多少子串的sg值不等于这个状态的sg值,再按拓扑序递推一下。
接下来就类似SPOJ 7258这道题了
从A串开始走,按字典序从小到大,定住A串后,根据在A串停住的状态的sg值再在B串上按拓扑序递推一次求出当前状态往后可以走出多少不等于这个sg值的子串,再在B串上按字典序从小到大走定住B串。
注意空串也算子串。
时间复杂度\(O(n\log n)\),只有求sg函数排序是\(O(n\log n)\)的,其他操作都是\(O(n)\)的。
调了好几天,很恶心啊,把c[nn + 1] = -1;
打成c[nn + 1] == -1;
了。
要是开-Wall就没这种事了qwq
在周赛结束前10分钟才发现错误,然后改过来A了233
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100003;
int tot = 0, cnt, cnt2;
struct State {
State *par, *go[26];
int val, sg; ll f;
} pool[N << 2], *id[N << 1], *tp[N << 1], *tp2[N << 1], *root_A, *root_B, *root, *last, *tmp;
State *newState(int num) {
pool[++tot].val = num;
pool[tot].par = 0;
pool[tot].sg = 0;
pool[tot].f = 0;
memset(pool[tot].go, 0, sizeof(pool[tot].go));
return id[++cnt] = &pool[tot];
}
void extend(int w) {
State *p = last;
State *np = newState(p->val + 1);
while (p && p->go[w] == 0)
p->go[w] = np, p = p->par;
if (p == 0) np->par = root;
else {
State *q = p->go[w];
if (q->val == p->val + 1) np->par = q;
else {
State *nq = newState(p->val + 1);
memcpy(nq->go, q->go, sizeof(nq->go));
nq->par = q->par;
q->par = np->par = nq;
while (p && p->go[w] == q)
p->go[w] = nq, p = p->par;
}
}
last = np;
}
char Sa[N], Sb[N], ansa[N], ansb[N];
int nn, c[N << 1], ansalen = 0, ansblen = 0;
ll sum[N], k;
void pre(int len) {
cnt2 = cnt;
for (int i = 1; i <= cnt; ++i) ++c[id[i]->val];
for (int i = 1; i <= len; ++i) c[i] += c[i - 1];
for (int i = cnt; i >= 1; --i) tp[c[id[i]->val]--] = id[i];
for (int i = cnt; i >= 1; --i) {
tp2[i] = tmp = tp[i];
nn = 0;
for (int w = 0; w < 26; ++w)
if (tmp->go[w]) {
tmp->f += tmp->go[w]->f;
c[++nn] = tmp->go[w]->sg;
}
++tmp->f;
stable_sort(c + 1, c + nn + 1);
if (c[1] != 0 || nn == 0) tmp->sg = 0;
else {
c[nn + 1] = -1;
for (int j = 1; j <= nn; ++j)
if (c[j] != c[j + 1] && c[j] + 1 != c[j + 1]) {
tmp->sg = c[j] + 1;
break;
}
}
}
}
void pre2(int len) {
memset(c, 0, sizeof(int) * (len + 1));
for (int i = 1; i <= cnt; ++i) ++c[id[i]->val];
for (int i = 1; i <= len; ++i) c[i] += c[i - 1];
for (int i = cnt; i >= 1; --i) tp[c[id[i]->val]--] = id[i];
for (int i = cnt; i >= 1; --i) {
tmp = tp[i];
nn = 0;
for (int w = 0; w < 26; ++w)
if (tmp->go[w]) {
tmp->f += tmp->go[w]->f;
c[++nn] = tmp->go[w]->sg;
}
stable_sort(c + 1, c + nn + 1);
if (c[1] != 0 || nn == 0) tmp->sg = 0;
else {
c[nn + 1] = -1;
for (int j = 1; j <= nn; ++j)
if (c[j] != c[j + 1] && c[j] + 1 != c[j + 1]) {
tmp->sg = c[j] + 1;
break;
}
}
tmp->f += sum[tmp->sg];
}
}
void work_B(int nu) {
for (int i = cnt2; i >= 1; --i) {
tmp = tp2[i]; tmp->f = 0;
for (int w = 0; w < 26; ++w)
if (tmp->go[w])
tmp->f += tmp->go[w]->f;
if (tmp->sg != nu) ++tmp->f;
}
tmp = root_B;
bool flag;
while (k) {
flag = false;
if (tmp->sg != nu) --k;
if (k == 0) {flag = true; break;}
for (int w = 0; w < 26; ++w)
if (tmp->go[w] && k)
if (tmp->go[w]->f >= k) {
flag = true;
tmp = tmp->go[w];
ansb[++ansblen] = 'a' + w;
break;
} else
k -= tmp->go[w]->f;
if (!flag) break;
}
if (!flag) puts("NO");
else {
for (int i = 1; i <= ansalen; ++i) putchar(ansa[i]); puts("");
for (int i = 1; i <= ansblen; ++i) putchar(ansb[i]); puts("");
}
}
int main() {
scanf("%lld%s%s", &k, Sa + 1, Sb + 1);
int lena = strlen(Sa + 1), lenb = strlen(Sb + 1);
cnt = 0;
root_B = root = last = newState(0);
for (int i = 1; i <= lenb; ++i)
extend(Sb[i] - 'a');
pre(lenb);
for (int i = 1; i <= cnt; ++i)
if (tp[i] != root_B) sum[tp[i]->sg] += tp[i]->val - tp[i]->par->val;
else ++sum[tp[i]->sg];
for (int i = 0; i <= lena; ++i)
sum[i] = root_B->f - sum[i];
cnt = 0;
root_A = root = last = newState(0);
for (int i = 1; i <= lena; ++i)
extend(Sa[i] - 'a');
pre2(lena);
tmp = root_A;
bool flag;
while (k) {
flag = false;
if (sum[tmp->sg] >= k) {
work_B(tmp->sg);
return 0;
}
k -= sum[tmp->sg];
for (int w = 0; w < 26; ++w)
if (tmp->go[w] && k)
if (tmp->go[w]->f >= k) {
flag = true;
ansa[++ansalen] = 'a' + w;
tmp = tmp->go[w];
break;
} else
k -= tmp->go[w]->f;
if (!flag) break;
}
puts("NO");
return 0;
}
【hihoCoder 1466】后缀自动机六·重复旋律9的更多相关文章
- HIHOcoder 1466 后缀自动机六·重复旋律9
思路 后缀数组+博弈论的好题,首先对两个串都建出SAM,然后题目的要求实际上就是在SAM的trans上转移即可 DAG的博弈是经典问题,然后dfs求出SG函数,两个游戏的组合就是把SG函数异或起来,异 ...
- hihoCoder #1445 : 后缀自动机二·重复旋律5
#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...
- hihoCoder #1465 : 后缀自动机五·重复旋律8
http://hihocoder.com/problemset/problem/1465 求S的循环同构串在T中的出现次数 将串S变成SS 枚举SS的每个位置i,求出以i结尾的SS的子串 与 T的最长 ...
- hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品 ...
- HIHOcoder 1457 后缀自动机四·重复旋律7
思路 后缀自动机题目,题目本质上是要求求出所有不同的子串的和,SAM每个节点中存放的子串互不相同,所以对于每个节点的sum,可以发现是可以递推的,每个点对子节点贡献是sum[x]*10+c*sz[x] ...
- hihocoder 1457 后缀自动机四·重复旋律7 ( 多串连接处理技巧 )
题目链接 分析 : 这道题对于单个串的用 SAM 然后想想怎么维护就行了 但是多个串下.可以先将所有的串用一个不在字符集( 这道题的字符集是 '0' ~ '9' ) 链接起来.建立后缀自动机之后 在统 ...
- hihoCoder #1457 : 后缀自动机四·重复旋律7(后缀自动机 + 拓扑排序)
http://hihocoder.com/problemset/problem/1457 val[i] 表示状态i所表示的所有字符串的十进制之和 ans= ∑ val[i]在后缀自动机上,从起始状态走 ...
- hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)
题目链接 \(Description\) 给定母串S,求模式串的循环同构串在S中的出现次数. \(Solution\) 将模式串s复制一遍,在母串的SAM上匹配,记录以每个位置作为后缀所能匹配的最大长 ...
- HIHOcoder 1449 后缀自动机三·重复旋律6
思路 显然endpos的大小就对应了对应子串的出现次数,所以快速求出endpos的大小,然后用它更新对应子串长度(minlen[i]~maxlen[i])的答案即可 endpos的大小可以拓扑排序求出 ...
随机推荐
- Pi
Math]Pi 数学知识忘地太快,在博客记录一下pi的生成. 100 Decimal places 3.1415926535897932384626433832795028841971693993 ...
- 基于认证的代理平台搭建配置squid-20130730
基于认证的代理平台搭建配置squid-20130730 功能:通过squid代理实现 (1)基于用户名密码认证的出口ip路由选择 (2)基于client源ip的出口ip路由选择 (3)基于连接本机ip ...
- 适合编写代码的字体 Source Code Pro
今天看到博客园一篇文章,介绍了一种出身自 Adobe 的适合编码的字体,等宽,支持ClearType等,试用一下吧 项目地址:https://github.com/adobe/source-code- ...
- NotePad++安装和配置C/C++开发插件
NotePad++ - 安装和配置C/C++开发插件 | NotePad++ - Install and Configure plugins for develop C/C++ http://aofe ...
- ios开发屏幕问题
1. 程序要要支持Iphone 和 ipad,所以首先必需创建一通用程序,这一操作只要在创建程序时在 devices那栏上勾选universal即可,完成后会发现有两个.xib文件,但只有一个view ...
- Oracle查询错误分析:ORA-01791:不是SELECTed表达式
表结构如下: create table HH_BOOK_GOOD ( ID VARCHAR2(32) not null, BOOKID VARCHAR2(32) not null, GOODID VA ...
- grunt 上手
grunt 上手 开始上手 Grunt 和 grunt 插件都是通过 npm 安装, Node.js 包管理器管理的. Grunt 0.4.x 版本需要Node.js 版本号不低于0.8.0. 一.安 ...
- FileTable初体验
FileTable初体验 阅读导航 启用FILESTREAM设置 更改FILESTRAM设置 启用数据库非事务性访问级别 FileTable 在我接触FileTable之前,存储文件都是存储文件的链接 ...
- 压缩文件 compress files 以7z 格式及解压 或者别的格式
主要是为了能大量的减少文件使用空间,为了能节约带宽. 那么就用了7z的压缩方式. 这里,使用了7z的压缩方式,硬生生的将一个10k多的图片压缩成了3k左右的包.图片是不好压缩的,这个压缩比比zip g ...
- Js-Html 前端系列--可伸缩菜单
一个非常经典的Demo,自行开发可以扩展. <head> <title></title> <style type="text/css"&g ...