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 机器翻译 模拟
题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先 ...
随机推荐
- js中字符串转数字的方法
1.当字符串中是纯数字 例如:var s = '234'; /********** 字符串在运算操作中会被当做数字类型来处理 ***************/ s *= 1; /******* str ...
- WPS处理个人信息一种方法
下面是WPS处理个人信息的方法,具体步骤如下: 第一步:任意打开一个文件: 第二步:点击左上角WPS的小三角,找到工具——选项,如图: 第三步:进入选项后,点击用户信息: 第四步:修改个人信息,用户名 ...
- 据说excel流是这么做,上次我分享的是csv格式。这个是excel格式。
import xlwt import StringIO import web urls = ( '/rim_request','rim_request', '/rim_export','rim_exp ...
- 关于collectionview布局的坑
不知道写了多少次collectionview,步了很多坑,现在看来虽然达到了自己想要的结果,却不知道其中所以然.还是总结一下,免得再走弯路: 场景是这样的,我要定制一个显示选择图片的排列,想要实现横向 ...
- Android : iperf-2.0.4 网络测试工具
一.源码下载及交叉编译: 下载:https://pan.baidu.com/s/1i6NYDF3 //包含linux和windows上的可执行文件 1. 解压后获得perf-2.0.4源码.2. ...
- 扩展HtmlHelper类实现Mvc4分页
1.扩展HtmlHelper类方法Pager public static HtmlString Pager(this HtmlHelper htmlHelper, int currentPage, i ...
- thinkphp5.1学习笔记
由于新公司使用的框架是thinkphp5.1,有必要进一步学习,看来我要把php框架使用完全了,之前就用过laravel和CI框架了. 现在打算只是一个学习的记录,结构会比较凌乱,基本我估计只能自己看 ...
- java学习笔记27(File类)
File类: 定义:文件和目录径的抽象表示形式, Java中将路径或者文件封装成File对象 1.File类的静态成员变量 package com.zs.Demo2; import java.io.F ...
- UUID自动生成
(uuid,available,createtime) select left(replace(uuid(), '-', ''),24),1,utc_timestamp() 使用: ),,utc_t ...
- python中闭包
闭包是指内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure). 闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变 ...