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 机器翻译 模拟
题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先 ...
随机推荐
- 房间安排 (nyoj 168)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=168 分析:找到一天中需要最多的房间即可 #include<iostream> ...
- 第三节 java 函数的封装方法 以及 访问封装内容
从我们的选择排序和冒泡排序里我们可以看到有很多相同的代码, 我们 可以把这些相同的代码提取出来封装为方法:比如我们的判 断交换和遍历输出: 抽取1: public static void PanDua ...
- 开窗函数 函数() OVER()
-- 初始化 CREATE TABLE T_Person (FName VARCHAR2(20), FCity VARCHAR2(20), FAge INT, FSalary INT); INSERT ...
- 1449 - The user specified as a definer('xxx'@'%') does not exist
指定的用户不存在,创建相应的账户即可,注意主机那里填的内容,我的这个是@'%'所以不用填任何内容.
- activemq 生产消费模式,订阅发布模式不同类型数据传输
1.项目结构 2. activemq-pom pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns ...
- SparkStreaming实时日志分析--实时热搜词
Overview 整个项目的整体架构如下: 关于SparkStreaming的部分: Flume传数据到SparkStreaming:为了简单使用的是push-based的方式.这种方式可能会丢失数据 ...
- 虚拟机提示:无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件
虚拟机提示:无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件 Win 10 vmware12 无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件. ...
- Linux下Ganglia集群监控安装、配置笔记
http://www.blogjava.net/henry14/archive/2011/12/17/ganglia.html 枪声依旧 Linux下Ganglia集群监控安装.配置笔记 Gangli ...
- 惊不惊喜, 用深度学习 把设计图 自动生成HTML代码 !
如何用前端页面原型生成对应的代码一直是我们关注的问题,本文作者根据 pix2code 等论文构建了一个强大的前端代码生成模型,并详细解释了如何利用 LSTM 与 CNN 将设计原型编写为 HTML 和 ...
- java学习笔记27(File类)
File类: 定义:文件和目录径的抽象表示形式, Java中将路径或者文件封装成File对象 1.File类的静态成员变量 package com.zs.Demo2; import java.io.F ...