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 机器翻译 模拟
题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先 ...
随机推荐
- 【资料收集】QT学习资料
几个专栏 Qt学习之路(3):Hello, world!(续) - 豆子空间 - 51CTO技术博客 http://devbean.blog.51cto.com/448512/194137 Qt 学习 ...
- oracle sqlserver mysql 通过sql查看表及字段注释
oracle: SELECT A.TABLE_NAME,A.COMMENTS,B.COLUMN_NAME,B.COMMENTS FROM USER_TAB_COMMENTS A,USER_COL_CO ...
- 【转载】JVM系列二:GC策略&内存申请、对象衰老
JVM里的GC(Garbage Collection)的算法有很多种,如标记清除收集器,压缩收集器,分代收集器等等,详见HotSpot VM GC 的种类 现在比较常用的是分代收集(generatio ...
- DevExpress v18.1新版亮点——Reporting篇(四)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress Reporting v18.1 的新功能,快来下载试用新版本 ...
- SharePoint online Multilingual support - Settings
博客地址:http://blog.csdn.net/FoxDave This post will talk about how to enable sharepoint online site mul ...
- 《深入分析Java Web技术内幕》读书笔记 - 第1章 深入Web请求过程
第1章 深入Web请求过程 1 1.1 B/S网络架构概述 2 基于统一的应用层协议HTTP来交互数据. 1.2 如何发起一个请求 4 HTTP连接本质是建立Socket连接.请求实现方式:工具包如H ...
- redis_key键
exists k1,判断k1是否存在,‘1’就是存在,‘0’ 就是不存在 move k3 2 --->这里就是说把k3移动到2号库. ‘1’为成功,‘0’为失败 ttl k2 --查看k2 ...
- day 46 前端基础 基本框架
注意一点 使用绝对路径的时候 在pxm里 打开显示不了图片 可以直接找到那个实际的网页去打开 还可能是图片的格式尽量用jpg一 详细解释 <!DOCTYPE html>声明为HTML5文档 ...
- nginx的日志切割
nginx日志默认情况下统统写入到一个文件中,文件会变的越来越大,非常不方便查看分析.以日期来作为日志的切割是比较好的,通常我们是以每日来做统计的.下面来说说nginx日志切割. 如果我们使用的是yu ...
- audit:backlog limit exceeded
今天发现存储服务器业务不可用,服务器能ping通,远程不了! 到机房管理员那里查看服务器状态后,发现显示如下: 显然系统已经崩溃,只能先重启服务器,先恢复业务,然后针对backlog limit e ...