【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的大小可以拓扑排序求出 ...
随机推荐
- C++构造 下一个排列 的函数
今天围观刘汝佳神犇的白书发现了一个好用的函数: next_permutation(); 可以用于可重, 或者不可重集, 寻找下一个排列. 时间复杂度尚不明. //适用于不可重和可重集的排列. # in ...
- DateTime 格式化
在格式化的时候,希望输出2013/10/01 但可能实际的输出是2013-10-01. string s1 = result.Item1.ToString("yyyy/MM/dd" ...
- 安装xdebug后var_dump输出没有格式化的问题
在ubuntu10.04下面配置Apache2.2 + PHP5.3的开发环境,顺便装了一个xdebug扩展方便调试代码. 但是环境配置好了之后却发现xdebug加载成功了但是var_dump输出的内 ...
- What skills are needed for machine learning jobs
What skills are needed for machine learning jobs?机器学习工作必须技能 原文: http://www.quora.com/Machine-Learnin ...
- IOC and DI
Spring.Net 技术简介 IOC and DI 一 简单介绍 IOC 控制转移,就是将创建放到容器里,从而达到接耦合的目的,DI是 在容器创建对象的时候,DI读取配置文 ...
- [每日一题] OCP1z0-047 :2013-07-29 视图――别名
本题的考点是如何创建视图,对于视图的详细知识点,可以参考我的博客: http://blog.csdn.net/guoyjoe/article/details/8614677 好,接下来我们来做测试,先 ...
- 将JSON映射为实体对象(iOS篇)
将JSON映射为实体对象(iOS篇) iOS开发人员已经习惯于将JSON转换为字典或者数组来进行操作了,接下来我要做的事情,可能匪夷所思,但是,对WP和Android开发人员而言,他们更倾向于将JSO ...
- Lucene.net入门学习系列(1)
Lucene.net入门学习系列(1) Lucene.net入门学习系列(1)-分词 Lucene.net入门学习系列(2)-创建索引 Lucene.net入门学习系列(3)-全文检索 这几天在公 ...
- Ubuntu 下的环境变量配置
网上很多配置jdk环境变量的方法,但是几乎都会下次重启电脑就失效,或者时不时的失效.下面教你一招 JDK环境变量配置如下: 执行命令sudo gedit /etc/environment,在打开的编辑 ...
- android.view.WindowManager$BadTokenException: Unable to add window — token null is not for an applic
之前遇到过这样的问题, 04-12 10:40:33.302: E/AndroidRuntime(17213): Caused by: android.view.WindowManager$BadTo ...