hdu4436-str2int(后缀数组 or 后缀自动机)
题意:给你一堆字符串,仅包含数字'0'到'9'。
例如 101 123
有一个字符串集合S包含输入的N个字符串,和他们的全部字串。
操作字符串很无聊,你决定把它们转化成数字。
你可以把一个字符串转换成一个十进制整数。
如果一个数字出现了多次,只留一个。
计算所有数字的和,模2012。
1<=N<=10000
题解:参考 http://blog.csdn.net/kqzxcmh/article/details/8122747
每个后缀的所有前缀就是所有子串。sa[i]和sa[i-1]有height[i]的长度是重复的,可以不考虑。
把字符串连起来,中间加分隔符,构成一个大的字符串,然后整体求后缀数组。
对于一个字符串123
可以v[0]=1 v[1]=12 v[3]=123 v[i]是0-i构成的数字
sum是前缀和 sum[0]=1 sum[1]=13 sum[2]=136
对于后缀23 sum[2]-sum[0] 得到 12+123的和
对于12需要减去10 对于123需要减去100
所以求l~r 首先需要sum[r]-sum[l-1], 然后设x=r-l
需要减去 for(int i=1;i<=x;++i) pow(10, i);
可以预处理出来。
太难辣!!像我这种辣鸡不适合这么难的题T^T
时限3s,187ms还是比较快的。
//后缀数组
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = int(2e5)+;
const int M = ; int cmp(int *r,int a,int b,int l){
return (r[a]==r[b]) && (r[a+l]==r[b+l]);
}
// 用于比较第一关键字与第二关键字,
// 比较特殊的地方是,预处理的时候,r[n]=0(小于前面出现过的字符) int wa[N],wb[N],wss[N],wv[N];
int sa[N]; // 排第i的是谁 i:1~n sa:0~n-1
int rk[N], // i排第几 i:0~n-1 rk:1~n
height[N]; // 排名相邻的两个后缀的最长公共前缀长度:suffix(sa[i-1])和(sa[i]) 的最长公共前缀,
char str[N]; void DA(char *r,int *sa,int n,int m){ // 此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界 m是不同的字符的个数
int i,j,p,*x=wa,*y=wb,*t;
for(i=;i<m;i++) wss[i]=;
for(i=;i<n;i++) wss[x[i]=r[i]]++;
for(i=;i<m;i++) wss[i]+=wss[i-];
for(i=n-;i>=;i--) sa[--wss[x[i]]]=i;
for(j=,p=;p<n;j*=,m=p)
{
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) wss[i]=;
for(i=;i<n;i++) wss[wv[i]]++;
for(i=;i<m;i++) wss[i]+=wss[i-];
for(i=n-;i>=;i--) sa[--wss[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=,x[sa[]]=,i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
} void calheight(char *r,int *sa,int n){ // 此处N为实际长度
int i,j,k=;
for(i=;i<=n;i++) rk[sa[i]]=i;
for(i=;i<n; height[rk[i++]] = k )
for(k?k--:,j=sa[rk[i]-]; r[i+k]==r[j+k]; k++);
} char word[N];
int d[N]; // 该字符串的结束位置
int sum[N];
int v[N];
int Pow[N]; int cal(int l, int r) {
if (l > r) return ;
//printf(">>%d %d %d %d %d\n", l, r, sum[r+1], sum[l], v[l]);
//printf("%d\n", ((sum[r+1]-sum[l]) - v[l]*Pow[r-l+1]%M + M) % M);
return ((sum[r+]-sum[l]) - v[l]*Pow[r-l+]%M + M) % M;
} int main(int argc, char const *argv[])
{
//freopen("in.txt", "r", stdin);
Pow[]=;Pow[]=;
for (int i=;i<N;++i)
Pow[i]=(Pow[i-]+)*%M;
int n;
while (~scanf("%d", &n)) {
int idx = ;
for (int i = ; i < n; ++i) {
scanf("%s", word);
int len = strlen(word);
int val = ;
for (int j = ; j < len; ++j) {
str[idx] = word[j] - '' + ;
val = (val * + str[idx] - ) % M;
v[idx+] = val; //+1是因为会有-1 <0很麻烦= =
sum[idx+] = (sum[idx] + val) % M;
d[idx] = len - j + idx;
idx++;
}
d[idx] = idx;
sum[idx+] = v[idx+] = ;
str[idx++] = ; //1~11
}
str[idx] = ;
DA(str, sa, idx+, );
calheight(str, sa, idx);
int ans = ;
for (int i = ; i < idx; ++i) {
if (str[i] == || str[i] == ) continue; // 不要前导零
int l = i + height[rk[i]];//重复的部分
int r = d[i]-;
//printf("i=%d,l=%d, r=%d\n", i, l, r);
if (l > r) continue;
ans = (ans + cal(i, r) - cal(i, l-)) % M;
//ans = (ans + cal(l, r)) % M; 这个不对 因为所求字符串是从i开始的
ans = (ans + M) % M;
}
printf("%d\n", ans);
}
return ;
}
后缀自动机= = 先留坑吧orz。。。。
hdu4436-str2int(后缀数组 or 后缀自动机)的更多相关文章
- [TJOI2015]弦论(后缀数组or后缀自动机)
解法一:后缀数组 听说后缀数组解第k小本质不同的子串是一个经典问题. 把后缀排好序后第i个串的本质不同的串的贡献就是\(n-sa[i]+1-LCP(i,i-1)\)然后我们累加这个贡献,看到哪一个串的 ...
- (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机
真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机
- 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)
模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...
- poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机
http://poj.org/problem?id=2774 我想看看这里的后缀数组:http://blog.csdn.net/u011026968/article/details/22801015 ...
- poj2774 Long Long Message(后缀数组or后缀自动机)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Long Long Message Time Limit: 4000MS Me ...
- 字符串 --- KMP Eentend-Kmp 自动机 trie图 trie树 后缀树 后缀数组
涉及到字符串的问题,无外乎这样一些算法和数据结构:自动机 KMP算法 Extend-KMP 后缀树 后缀数组 trie树 trie图及其应用.当然这些都是比较高级的数据结构和算法,而这里面最常用和最熟 ...
- bzoj 3172 后缀数组|AC自动机
后缀数组或者AC自动机都可以,模板题. /************************************************************** Problem: 3172 Us ...
- SPOJ694 DISUBSTR --- 后缀数组 / 后缀自动机
SPOJ694 DISUBSTR 题目描述: Given a string, we need to find the total number of its distinct substrings. ...
- POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)
Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...
随机推荐
- HDU 1883 Phone Cell (圆覆盖最多点)
题目链接 题意 : 给你很多点和一个半径r,这个半径为r的圆能覆盖的最多的点是多少. 思路 : 对每个点做半径为 r 的圆, 求交集,交集最多的区域的被覆盖次数就是能覆盖的最多的点.贴两个链接,分析的 ...
- HDU 2992 Hotel booking(BFS+DFS 或者 SPFA+Floyd)
点我看题目 题意 : 一个司机要从1点到达n点,1点到n点中有一些点有宾馆,司机的最长开车时间不能超过10小时,所以要在10小时之内找到宾馆休息,但是为了尽快的走到n点,问最少可以经过几个宾馆. 思路 ...
- 编程实现Windows关机、重启、注销
要想编程使Windows关机.重启或者注销,可以使用ExWindowsEx这个API函数,该函数只有两个参数,第一个表示关机动作的标志,也就是你要让该函数关机呢,还是重启,还是注销等.可以使用EWX_ ...
- 102. Binary Tree Level Order Traversal
题目: Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to ri ...
- Android sd卡读取数据库
先在 Manifest 里添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE&q ...
- MySQL数据库乱码 - Linux下乱码问题一
乱码问题是很让人抓狂的问题,下面我将记录一下linux下mysql乱码问题的解决方法. mysql在linux下乱码问题 一.操作 mysql默认字符集是latin1,但是我们大部分程序使用的字符集是 ...
- Hadoop集群安装配置教程_Hadoop2.6.0_Ubuntu/CentOS
摘自:http://www.powerxing.com/install-hadoop-cluster/ 本教程讲述如何配置 Hadoop 集群,默认读者已经掌握了 Hadoop 的单机伪分布式配置,否 ...
- 理解Java对象序列化(二)
关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制.在撰写本文时,既参考了Th ...
- JXL获取excel批注
/** * Jxl.jar(2.6.12) * @author lmiky * @date 2011-11-26 */ public class JxlTest { /** * 测试获取批注 * @a ...
- uva753 A Plug for UNIX
最大流. 流可以对应一种分配方式. 显然最大流就可以表示最多匹配数 #include<cstdio> #include<algorithm> #include<cstri ...