Solution

傻X题

我的方法是建立后缀后缀树, 然后在DFS序列上直接二分即可.

关键在于如何得到后缀树上每个字符对应的字节点: 我们要在后缀自动机上记录每个点在后缀树上对应的字母. 考虑如何实现, 我们在后缀自动机上的每个状态上, 记录其所对应的在字符串中的位置, 减去其父亲节点的长度即可得到每个节点对应的后缀树上的字符.

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
const int LEN = (int)2e5;
struct suffixAutomaton
{
int tp, rt, L, R;
struct node
{
int suc[26], pre;
int endPosition, len, c;
int vst;
int successorOnSuffixTree[26];
inline node() {memset(suc, -1, sizeof(suc)); pre = -1; vst = 0; memset(successorOnSuffixTree, -1, sizeof(successorOnSuffixTree));}
}nd[LEN << 1];
void DFS(int u)
{
nd[u].vst = 1; if(u != rt) nd[nd[u].pre].successorOnSuffixTree[nd[u].c] = u;
for(int i = 0; i < 26; ++ i) if(~ nd[u].suc[i] && ! nd[nd[u].suc[i]].vst) DFS(nd[u].suc[i]);
}
int clk;
int idx[LEN << 1], sz[LEN << 1];
long long sum[LEN << 1];
inline void getId(int u)
{
int cur = clk ++;
idx[cur] = u; sz[cur] = u == rt ? 0 : nd[u].len - nd[nd[u].pre].len;
for(int i = 0; i < 26; ++ i) if(~ nd[u].successorOnSuffixTree[i])
{
int v = nd[u].successorOnSuffixTree[i];
getId(v);
if(nd[u].endPosition == -1 || nd[u].endPosition > nd[v].endPosition) nd[u].endPosition = nd[v].endPosition;
}
}
inline void build(char *str, int len)
{
L = R = 0;
rt = 0; nd[rt].len = 0; tp = 1;
int lst = rt;
for(int i = len - 1; ~ i; -- i)
{
char c = str[i] - 'a';
int u = tp ++; nd[u].len = nd[lst].len + 1; nd[u].endPosition = i;
for(; ~ lst && nd[lst].suc[c] == -1; lst = nd[lst].pre) nd[lst].suc[c] = u;
if(lst == -1) nd[u].pre = rt, nd[u].c = str[i] - 'a';
else
{
int p = nd[lst].suc[c];
if(nd[p].len == nd[lst].len + 1) nd[u].pre = p, nd[u].c = str[i + nd[p].len] - 'a';
else
{
int q = tp ++;
memcpy(nd[q].suc, nd[p].suc, sizeof(nd[p].suc)); nd[q].pre = nd[p].pre; nd[q].len = nd[lst].len + 1; nd[q].endPosition = i;
// we must set nd[q].endPosition's value right now, 'cause it may be used later
nd[q].c = str[i + nd[nd[q].pre].len] - 'a';
nd[p].pre = nd[u].pre = q;
nd[p].c = str[nd[p].endPosition + nd[q].len] - 'a'; nd[u].c = str[i + nd[q].len] - 'a';
for(; ~ lst && nd[lst].suc[c] == p; lst = nd[lst].pre) nd[lst].suc[c] = q;
}
}
lst = u;
}
DFS(rt);
clk = 0; getId(rt);
sum[0] = sz[0]; for(int i = 1; i < tp; ++ i) sum[i] = sum[i - 1] + sz[i];
}
inline void query(long long k)
{
k = (long long)(L ^ R ^ k) + 1;
// int k = v;
int curL = 0, curR = tp - 1, pos = -1;
while(curL <= curR)
{
int mid = curL + curR >> 1;
if(sum[mid] >= k) {pos = mid; curR = mid - 1;} else curL = mid + 1;
}
if(pos == -1) {L = 0; R = 0; printf("%d %d\n", L, R); return;}
L = nd[idx[pos]].endPosition + 1; R = L + (k - sum[pos - 1] + nd[nd[idx[pos]].pre].len) - 1;
printf("%d %d\n", L, R);
}
}SAM;
int main()
{ #ifndef ONLINE_JUDGE freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout); #endif static char str[LEN]; scanf("%s", str);
SAM.build(str, strlen(str));
int m; scanf("%d", &m);
long long v;
for(int i = 0; i < m; ++ i) scanf("%lld", &v), SAM.query(v);
}

2016集训测试赛(十九)Problem C: 无聊的字符串的更多相关文章

  1. 2016集训测试赛(十九)Problem A: 24点大师

    Solution 这到题目有意思. 首先题目描述给我们提供了一种非常管用的模型. 按照题目的方法, 我们可以轻松用暴力解决20+的问题; 关键在于如何构造更大的情况: 我们发现 \[ [(n + n) ...

  2. 2016集训测试赛(二十六)Problem A: bar

    Solution 首先审清题意, 这里要求的是子串而不是子序列... 我们考虑用1表示p, -1表示j. 用sum[i]表示字符串前\(i\)的前缀和. 则我们考虑一个字符串\([L, R]\)有什么 ...

  3. 2016集训测试赛(二十四)Problem B: Prz

    Solution 这道题有两个关键点: 如何找到以原串某一个位置为结尾的某个子序列的最晚出现位置 如何找到原串中某个位置之前的所有数字的最晚出现位置中的最大值 第一个关键点: 我们注意到每个数字在\( ...

  4. 2016集训测试赛(二十四)Problem C: 棋盘控制

    Solution 场上的想法(显然是错的)是这样的: 我们假设棋子是一个一个地放置的, 考虑在放置棋子的过程中可能出现哪些状态. 我们令有序整数对\((i, j)\)表示总共控制了\(i\)行\(j\ ...

  5. 2016集训测试赛(二十)Problem B: 字典树

    题目大意 你们自己感受一下原题的画风... 我怀疑出题人当年就是语文爆零的 下面复述一下出题人的意思: 操作1: 给你一个点集, 要你在trie上找到所有这样的点, 满足点集中存在某个点所表示的字符串 ...

  6. 2016集训测试赛(二十)Problem A: Y队列

    Solution 考虑给定一个\(n\), 如何求\(1\)到\(n\)的正整数中有多少在队列中. 不难注意到我们只需要处理质数次方的情况即可, 因为合数次方会被其因数处理到. 同时我们考虑到可能存在 ...

  7. 2016集训测试赛(十八)Problem C: 集串雷 既分数规划学习笔记

    Solution 分数规划经典题. 话说我怎么老是忘记分数规划怎么做呀... 所以这里就大概写一下分数规划咯: 分数规划解决的是这样一类问题: 有\(a_1, a_2 ... a_n\)和\(b_1, ...

  8. 2016北京集训测试赛(九)Problem C: 狂飙突进的幻想乡

    Solution 我们发现, 对于一条路径来说, 花费总时间为\(ap + q\), 其中\(p\)和\(q\)为定值. 对于每个点, 我们有多条路径可以到达, 因此对于每个区间中的\(a\)我们可以 ...

  9. 2016集训测试赛(二十一)Problem C: 虫子

    题目大意 给你一棵树, 每个点有一个点权. 有两种操作: link / cut 修改某个点的点权 每次操作后, 你要输出以下答案: 在整棵树中任意选两个点, 这两个点的LCA的期望权值. Soluti ...

随机推荐

  1. Java面试——多线程面试题总结

    )两者都在等待对方所持有但是双方都不释放的锁,这时便会一直阻塞形成死锁. //存放两个资源等待被使用 public class Resource { public static Object obj1 ...

  2. Struts1 部分源码学习

    Struts1工作原理    1.系统初始化(读取配置):初始化ModuleConfig对象       Struts框架是一个总控制器(ActionServlet)是一个Servlet,在web.x ...

  3. Java中BigInteger类型

    BigInteger是java.math包提供的处理大整数类型,实现了大整数的存储,四则运算,判断素数的方法,求幂,求模,求逆元,求最大公约数等方法.本文主要分析下BigInteger对于大整数的存储 ...

  4. Android输入法弹出时覆盖输入框问题

    本文来自网易云社区 作者:孙有军 当一个activity中含有输入框时,我们点击输入框,会弹出输入法界面,整个界面的变化效果与manifest中对应设置的android:windowSoftInput ...

  5. STL学习笔记6 -- 栈stack 、队列queue 和优先级priority_queue 三者比较

    栈stack  .队列queue  和优先级priority_queue 三者比较 默认下stack 和queue 基于deque 容器实现,priority_queue 则基于vector 容器实现 ...

  6. Google Chrome开发者工具-移动仿真:触摸事件仿真

    如果你在开发PAD/手机所用WEB版应用,需要在桌面审查页面元素.调试脚本,模拟移动设备尺寸.事件.位置等信息, 那么可以使用Chrome开发者工具(DevTools)提供的强大的移动仿真功能,支持主 ...

  7. Leetcode 532.数组中的K-diff数对

    数组中的K-diff数对 给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对.这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字 ...

  8. 实用拜占庭容错算法PBFT

    实用拜占庭容错算法PBFT 实用拜占庭容错算法PBFT 96 乔延宏 2017.06.19 22:58* 字数 1699 阅读 4972评论 0喜欢 11 分布式架构遭遇的问题 分布式架构会遭遇到以下 ...

  9. mongodb的安装和sql操作

    mongodb安装环境:centos6.5https://www.mongodb.org/dl/linux/x86_64wget https://fastdl.mongodb.org/linux/mo ...

  10. Zabbix整合MegaCLI实现物理硬盘的自动发现和监控

    MegaCLI是LSI提供的用户空间管理RAID卡(LSI芯片)工具,适用于大多数的Dell服务器. MegaCLI介绍: http://zh.community.dell.com/techcente ...