CodeChef KILLKTH Killjee and k-th letter
题意
dt {
font-weight: bold;
margin-top: 20px;
padding-left: 35px;
}
dd {
box-shadow: 3px 3px 6px #888888;
background-color: rgba(210, 210, 255, 0.5);
padding: 20px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
font-family: "Merriweather", serif;
font-size: 18px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.desc-container {
color: rgba(210, 210, 255, 0.5);;
}
pre {
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>
<dt></dt>
<dd>
Read problems statements in Mandarin chinese, Russian and Vietnamese as well.
Killjee is trying to unlock a treasure. The key to the treasure is encrypted using a string S and Q queries. In each query, you need to find the K-th letter of a hidden string which is formed from the string S.
To form the hidden string, you should sort all substrings of S in lexicographical order and concatenate them. For example, if S = "abc", the hidden string would be "aababcbbcc". (See the sample explanation for details.)
In each query, the value of K is encoded in the following way:
- You're given two integers P and M.
- Let's define G as the sum of ASCII values of answers to all previous queries (therefore, G = 0 for the first query).
- The value of K for the current query is ( P · G ) % M + 1, where % denotes the modulo operator.
Input
- The first line of the input contains a single string S.
- The second line contains a single integer Q.
- Q lines follow. Each of these lines contains two space-separated integers P and M.
Output
For each query, print a single line containing one character — the K-th letter of the hidden string.
Constraints
- 1 ≤ |S| ≤ 2 · 105
- 1 ≤ Q ≤ 2 · 105
- 1 ≤ K,M ≤ length of hidden string
- 1 ≤ P ≤ 109
- S will consist only of lowercase English letters
Subtasks
Subtask #1 (5 points): 1 ≤ |S| ≤ 50
Subtask #2 (15 points):
- 1 ≤ |S| ≤ 2000
- 1 ≤ Q ≤ 25000
Subtask #3 (20 points): 1 ≤ Q ≤ 10
Subtask #4 (60 points): original constraints
Example
Input: abc
3
1 1
2 3
5 6 Output: a
b
a
Explanation
The substrings of S are "a", "b", "c", "ab", "abc", "bc". The lexicographical order of these strings is "a", "ab", "abc", "b", "bc", "c", so the hidden string is "a"+"ab"+"abc"+"b"+"bc"+"c" = "aababcbbcc".
For query 1, G = 0, so K = ( P · G ) % M + 1 = ( 1 · 0 ) % 1 + 1 = 1. The 1-st character of the hidden string is 'a'. We add the ASCII value of 'a' (97) to G.
For query 2, G = 97, so K = ( 2 · 97 ) % 3 + 1 = 3. The 3-rd character of the hidden string is 'b'. We add the ASCII value of 'b' (98) to G.
For query 3, G = 195, so K = ( 5 · 195 ) % 6 + 1 = 4. The 4-th character of the hidden string is 'a'. We add the ASCII value of 'a' (97) to G.
字母(letter)
给定一个字符串S。取出S的所有子串,并按字典序从小到大排序,然后将这些排完序的字符串首尾相接,记为字符串T。有Q次询问,每次询问T中的第K个字符。
K是被加密的,每次询问给出两个正整数P, M,设G为之前所有询问答案的 ASCII 码之和。初始时G为0。则该次询问的K = (P ∗ G) mod M。
分析
跟所有子串有关,那肯定要么是后缀自动机,要么是后缀树。
考虑后缀自动机。即使后缀自动机单次询问可以做到线性,在这题也无施展之地。鉴于他DAWG的性质,没有什么东西可以维护。
然而后缀树就不一样了,[TJOI2015] 弦论有一种\(O(n+\log n)\)的做法,可以参考Mangoyang的博客。
实际上考虑 parent 可以进一步优化算法的复杂度,考虑原先的 parent 树一个节点代表的多个串都是最长的串的一个后缀,是一棵类似于前缀树的结构,这样不能适用于一些字典序上优美的性质。不妨将串反序插入到sam 中,这样每一个点能代表的多个串都是最长的串的前缀,这些串从长到短在字典序上一定是有序的。扩展到整棵树上,根据 \(minlen(u)=len(fa(u))+1\) ,每个点代表的字符串都比其祖先代表的字符串的字典序大。于是可以计算出每一棵子树代表了多少串,在 dfn 序上二分答案即可
类似的,也可以计算出后缀树每一颗子树代表的串的总长,并且通过构造可以使后缀树上字符串的字典序与 dfn 序同时有序。这样找到了后缀树上的一个节点后,考虑一个子串其所代表的串长度在 \([len(fa(u))+1,len(u)]\) 上连续,在这个节点上继续二分答案就可以找到第k个字符所在的子串及它的长度,再计算一下就能知道第k个字符在s中的位置了。时间复杂度\(O(n+q\log n)\)
后缀自动机本身之所以不能做这些事情,是因为没有很好的性质维护字典序。如果用dfs把所有路径按字典序找出来然后标号,节点重用很少,个数期望就是\(O(n^2)\)个。
代码
十年OI一场空,不开long long见祖宗。
co int N=4e5+10;
char s[N];
int n,last=1,tot=1;
int ch[N][26],len[N],fa[N],pos[N],siz[N];
il void extend(int c,int po){
int p=last,cur=last=++tot;
len[cur]=len[p]+1,pos[cur]=po,siz[cur]=1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++tot;
copy(ch[q],ch[q]+26,ch[clone]);
len[clone]=len[p]+1,fa[clone]=fa[q],pos[clone]=pos[q];
fa[q]=fa[cur]=clone;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
int cnt[N],ord[N],e[N][26],ref[N],dfn;
ll sum[N];
void dfs(int u){
::ref[++dfn]=u;
sum[dfn]=(ll)siz[u]*(len[u]+len[fa[u]]+1)*(len[u]-len[fa[u]])/2;
for(int i=0;i<26;++i)if(e[u][i]) dfs(e[u][i]);
}
il int query(ll k){
int l=1,r=tot,mid;
while(l<r) sum[mid=l+r>>1]>=k?r=mid:l=mid+1;
k-=sum[l-1];
int x=::ref[l];
l=len[fa[x]]+1,r=len[x];
while(l<r){
mid=l+r>>1;
if((ll)siz[x]*(mid+len[fa[x]]+1)*(mid-len[fa[x]])/2>=k) r=mid;
else l=mid+1;
}
k-=(ll)siz[x]*(l+len[fa[x]])*(l-1-len[fa[x]])/2;
k=(k-1)%l+1;
return s[pos[x]+k-1];
}
int main(){
// freopen("letter.in","r",stdin),freopen("letter.out","w",stdout);
scanf("%s",s+1),n=strlen(s+1);
for(int i=n;i>=1;--i) extend(s[i]-'a',i);
for(int i=1;i<=tot;++i) ++cnt[len[i]];
for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
for(int i=1;i<=tot;++i) ord[cnt[len[i]]--]=i;
for(int i=tot;i;--i) siz[fa[ord[i]]]+=siz[ord[i]];
for(int i=1;i<=tot;++i) e[fa[i]][s[pos[i]+len[fa[i]]]-'a']=i;
dfs(1),assert(dfn==tot);
for(int i=1;i<=dfn;++i) sum[i]+=sum[i-1];
ll G=0,P,M;
for(int Q=read<int>(),c;Q--;G+=c){
read(P),read(M);
printf("%c\n",c=query(P*G%M+1));
}
return 0;
}
CodeChef KILLKTH Killjee and k-th letter的更多相关文章
- 【干货】”首个“ .NET Core 验证码组件
前言 众所周知,Dotnet Core目前没有图形API,以前的System.Drawing程序集并没有包含在Dotnet Core 1.0环境中.不过在dotnet core labs项目里可以见到 ...
- PHPExcel使用体会
PHPExcel使用体会 因为毕设导师智能分配系统的需要,系负责人在管理学生和导师时,希望可以使用Excel批量导入学生和导师的信息,学长的报课系统使用的是PHPExcel的类库,于是我也抽空花了2天 ...
- Android学习笔记(十)——ListView的使用(上)
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! ListView绝对可以称得上是 Android中最常用的控件之一,ListView允许用户通过手指上下滑动的 ...
- CCF认证(1)
#include <iostream> #include <windows.h> using namespace std; typedef struct letter{ int ...
- 424. Longest Repeating Character Replacement
以最左边为开始,往右遍历,不一样的个数大于K的时候停止,回到第一个不一样的地方,以它为开始,继续.. 用QUEUE记录每次不一样的INDEX,以便下一个遍历开始, 从左往右,从右往左各来一次..加上各 ...
- ASCII 码对应表
Macron symbol ASCII CODE 238 : HTML entity : [ Home ][ español ] What is my IP address ? your public ...
- [Swift]LeetCode880. 索引处的解码字符串 | Decoded String at Index
An encoded string S is given. To find and write the decodedstring to a tape, the encoded string is ...
- CF613E Puzzle Lover
题意 英文版题面 Problems Submit Status Standings Custom test .input-output-copier { font-size: 1.2rem; floa ...
- P1540 机器翻译 模拟
题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先 ...
随机推荐
- 软件测试职业规划的思考(转)(作者Findyou
前言 入软件测试行至今已经8年多,承领导们的信任与重用,同事的支持与信任,我的职业发展算是相对较好,从入行到各类测试技术岗位,再到测试总监,每一步都刚刚好.最近在自身职业发展瓶颈,人生十字路口,静坐反 ...
- 【转载】《Learn More Study Less》整体性学习方法
原文 忘记在哪里看到这本书的介绍了,据说是一个小子自学1年,完成了4年麻省理工的课程,然后写了一本他学习方法的书.我搜了一下,居然中英文版都有,就花时间好好读了一遍,就是这本. 以下是这本书的完整笔记 ...
- UIScrollview的 约束 contentsize contentoffset contentinset layoutsubviews needlayout等影响布局的属性
很久没有写视图布局,最近发现写布局很不顺手,总结一下在处理UIScrollview的时候种种注意事项: 1. self.automaticallyAdjustsScrollViewInsets = N ...
- Android system :灯光系统_HAL_lights
一.android灯光系统框架: Java: frameworks/base/services/core/java/com/android/server/lights/LightsService.ja ...
- windows下安装cygwin及配置(转)
reference:https://cygwin.com/install.html 对比:MinGW vs. CygWin https://www.cnblogs.com/findumars/p ...
- Android开发 ---基本UI组件3:单选按钮、多选按钮、下拉列表、提交按钮、重置按钮、取消按钮
Android开发 ---基本UI组件2 1.activity_main.xml 描述: 定义一个用户注册按钮 <?xml version="1.0" encoding=&q ...
- 人生苦短,我用python,为什么选择python,python简介
认识 Python 人生苦短,我用 Python —— Life is short, you need Python  目标 Python 的起源 为什么要用 Python? Python 的特点 ...
- GNU C的定义长度为0的数组
在标准C和C++中,长度为0的数组是被禁止使用的.不过在GNU C中,存在一个非常奇怪的用法,那就是长度为0的数组,比如Array[0];很多人可能觉得不可思议,长度为0的数组是没有什么意义的,不过在 ...
- oracle语句优化
摘录来自https://blog.csdn.net/sap_jack/article/details/3766703 1.选用适合的Oracle优化器 Oracle的优化器共有3种: a.RULE(基 ...
- Mybatis级联,使用JOIN和Associa,以及一些ID覆盖和自动变换。
先说下坑,比如数据库的字段是 DW_ID ,用generator讲mybatis自动转换的时候,会省略下表_变成dwId,所以我们之后自己手动设计的时候也尽量换成dwId: generate的myb ...