HDU 4622 多校第三场1002 后缀自动机
比赛的时候我是用后缀数组的,但是T了。
赛后看了解题报告说,后缀数组貌似是卡你常数的时间,我算了下复杂度O(T * Q * n)。这是10 ^ 8,但是考虑到每次询问的时候都要重新构造字符,所以那个n可能是(3 - 4 ) * n,卡的可能就是这个常数。然后就过不了了。
我先上一发我的后缀数组的代码,T的好惨。
因为当时不会后缀自动机。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include <cstdio>
using namespace std;
const int N=2005;
/****后缀数组模版****/
#define F(x)((x)/3+((x)%3==1?0:tb)) //F(x)求出原字符串的suffix(x)在新的字符串中的起始位置
#define G(x)((x)<tb?(x)*3+1:((x)-tb)*3+2) //G(x)是计算新字符串的suffix(x)在原字符串中的位置,和F(x)为互逆运算
int wa[N],wb[N],wv[N],WS[N];
int sa[N*3] ;
int rank1[N],height[N];
int r[N*3]; int c0(int *r,int a,int b) {
return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
}
int c12(int k,int *r,int a,int b) {
if(k==2)
return r[a]<r[b] || ( r[a]==r[b] && c12(1,r,a+1,b+1) );
else
return r[a]<r[b] || ( r[a]==r[b] && wv[a+1]<wv[b+1] );
}
void sort(int *r,int *a,int *b,int n,int m) {
int i;
for(i=0; i<n; i++)
wv[i]=r[a[i]];
for(i=0; i<m; i++)
WS[i]=0;
for(i=0; i<n; i++)
WS[wv[i]]++;
for(i=1; i<m; i++)
WS[i]+=WS[i-1];
for(i=n-1; i>=0; i--)
b[--WS[wv[i]]]=a[i];
return;
} //注意点:为了方便下面的递归处理,r数组和sa数组的大小都要是3*n
void dc3(int *r,int *sa,int n,int m) { //rn数组保存的是递归处理的新字符串,san数组是新字符串的sa
int i , j , *rn = r+n , *san = sa+n , ta = 0 ,tb = (n+1)/3 , tbc = 0 , p;
r[n] = r[n+1] = 0;
for(i=0; i<n; i++) {
if(i%3!=0)
wa[tbc++]=i; //tbc表示起始位置模3为1或2的后缀个数
}
sort(r+2,wa,wb,tbc,m);
sort(r+1,wb,wa,tbc,m);
sort(r,wa,wb,tbc,m);
for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)
rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
if(p<tbc)
dc3(rn,san,tbc,p);
else {
for(i=0; i<tbc; i++)
san[rn[i]]=i;
}
//对所有起始位置模3等于0的后缀排序
for(i=0; i<tbc; i++) {
if(san[i]<tb)
wb[ta++]=san[i]*3;
}
if(n%3==1) //n%3==1,要特殊处理suffix(n-1)
wb[ta++]=n-1;
sort(r,wb,wa,ta,m);
for(i=0; i<tbc; i++)
wv[wb[i]=G(san[i])]=i;
//合并所有后缀的排序结果,保存在sa数组中
for(i=0,j=0,p=0; i<ta&&j<tbc; p++)
sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(; i<ta; p++)
sa[p]=wa[i++];
for(; j<tbc; p++)
sa[p]=wb[j++];
return;
} //height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
void calheight(int *r,int *sa,int n) {
int i,j,k=0;
for(i=1; i<=n; i++)
rank1[sa[i]]=i;
for(i=0; i<n; height[rank1[i++]]=k)
for(k?k--:0,j=sa[rank1[i]-1]; r[i+k]==r[j+k]; k++);
}
int solve(int n) {
int i,sum=0;
for(i=1; i<=n; i++) {
sum += n - sa[i] - height[i] ;
} return sum;
}
/****以上模版****/
char now[2005] ;
char str[N];
inline void RD(int &ret) {
char c;
do {
c = getchar();
} while(c < '0' || c > '9') ;
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
}
inline void OT(int a) {
if(a >= 10)OT(a / 10) ;
putchar(a % 10 + '0') ;
}
struct QU {
int s ,e ,id ;
} QQ[10005] ;
bool cmp(QU a ,QU b) {
if(a.s == b.s)return a.e < b.e ;
return a.s < b.s ;
}
int ans[11111] ;
int main() {
int i,n,t;
scanf("%d",&t);
while(t--) {
scanf("%s",str);
memset(ans , 0 , sizeof(ans));
int xd ;
cin >> xd ;
for (int i = 0 ; i < xd ; i ++ ) {
RD(QQ[i].s) ;
RD(QQ[i].e) ;
QQ[i].s -- ;
QQ[i].e -- ;
QQ[i].id = i ;
}
sort(QQ , QQ + xd , cmp) ;
int st = QQ[0].s ;
int ed = QQ[0].e ;
int num = 0 ;
for (int i = st ; i <= ed ; i ++ )r[num ++] = (int)str[i] ;
r[num] = 0 ;
dc3(r , sa ,num + 1 , 200) ;
calheight(r , sa, num ) ;
ans[QQ[0].id] = solve(num) ;
for (int i = 1 ; i < xd ; i ++ ) {
if(QQ[i].s != QQ[i - 1].s) {
num = 0 ;
for (int j = QQ[i].s ; j <= QQ[i].e ; j ++ )r[num ++] = (int)str[j] ;
r[num] = 0 ;
dc3(r , sa , num + 1 ,200 ) ;
calheight(r ,sa ,num) ;
ans[QQ[i].id] = solve(num) ;
ed = QQ[i].e ;
} else {
if(QQ[i].e == QQ[i - 1].e) {
ans[QQ[i].id] = ans[QQ[i - 1].id] ;
} else {
for (int j = ed + 1 ; j <= QQ[i].e ; j ++)r[num ++] = (int)str[j] ;
r[num] = 0 ;
dc3(r ,sa ,num + 1 , 200) ;
calheight(r ,sa ,num) ;
ans[QQ[i].id] = solve(num) ;
ed = QQ[i].e ;
}
}
}
for (int i = 0 ; i < xd ; i ++ ) {
OT(ans[i]) ;
puts("") ;
}
}
return 0;
}
昨天晚上和今天一直在看后缀自动机,这里推荐一个我看的懂的博客。
http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html
算是学会了使用模版。当然也仅限于模版题。。好水。。继续学习。。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2505
#define inf 1<<28
#define LL(x) ( x << 1 )
#define RR(x) ( x << 1 | 1 )
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define PII pair<int,int>
using namespace std; inline void RD(int &ret) {
char c;
do {
c = getchar();
} while(c < '0' || c > '9') ;
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
}
inline void OT(int a){
if(a >= 10)OT(a / 10) ;
putchar(a % 10 + '0') ;
}
struct SAM {
SAM*pre ,*next[26] ;
int val ;
void clear() {
pre = 0 ;
val = 0 ;
mem(next ,0) ;
}
} ;
SAM *root ,*last ,*cur ;
SAM qe[111111] ;
int cnt = 0 ;
void init() {
cnt = 0 ;
root = last = &qe[cnt ++] ;
root -> clear() ;
}
struct QU{
int s ,e ,id ;
}QQ[100005] ;
void extend(int w ) {
SAM*p = last ;
SAM*np = &qe[cnt ++] ;
np -> clear() ;
np -> val = p -> val + 1 ;
while(p && !p -> next[w] )p -> next[w] = np ,p = p -> pre ;
if(!p) {
np -> pre = root ;
} else {
SAM *q = p -> next[w] ;
if(p -> val + 1 == q -> val) {
np -> pre = q ;
} else {
SAM *nq = &qe[cnt ++] ;
nq -> clear() ;
memcpy(nq -> next ,q -> next ,sizeof(q -> next)) ; nq -> val = p -> val + 1 ;
nq -> pre = q -> pre ;
q -> pre = nq ;
np -> pre = nq ;
while(p && p -> next[w] == q) {
p -> next[w] = nq ;
p = p -> pre ;
}
}
}
last = np ;
} #define N 100005
#define M 2005
char a[M] ;
bool cmp(QU a ,QU b){
if(a.s == b.s)return a.e < b.e ;
return a.s < b.s ;
}
int solve(){
int sum = 0 ;
for (int i = cnt - 1 ; i > 0 ; i -- ){
sum += qe[i].val - qe[i].pre -> val ;
}
return sum ;
}
int ans[N] ;
int main() {
int T ;
cin >> T ;
while( T -- ) {
cin >> a ;
mem(ans, 0) ;
int l = strlen(a) ;
int Q ;
cin >> Q ;
for (int i = 0 ; i < Q ; i ++ ){
RD(QQ[i].s) ;
RD(QQ[i].e) ;
QQ[i].s -- ;
QQ[i].e -- ;
QQ[i].id = i ;
}
sort(QQ , QQ + Q , cmp) ;
init() ;
int st = QQ[0].s ;
int ed = QQ[0].e ;
for (int i = st ; i <= ed ; i ++ ){
extend(a[i] - 'a') ;
}
for (int i = cnt - 1 ; i > 0 ; i -- ){
ans[QQ[0].id] += qe[i].val - qe[i].pre -> val ;
}
for (int i = 1 ; i < Q ;i ++ ){
// cout << QQ[i].s << " " << QQ[i].e << endl;
// getchar() ;
if(QQ[i].s != QQ[i - 1].s){
init() ;
for (int j = QQ[i].s ; j <= QQ[i].e ; j ++ )extend(a[j] - 'a' ) ;
ans[QQ[i].id] = solve() ;
}
else {
if(QQ[i].e == QQ[i - 1].e){
ans[QQ[i].id] = ans[QQ[i - 1].id] ;
}else{
for (int j = ed + 1 ; j <= QQ[i].e ; j ++ )extend(a[j] - 'a' ) ;
ans[QQ[i].id] = solve() ;
}
}
ed = QQ[i].e ;
}
for (int i = 0 ; i < Q ;i ++ ){
OT(ans[i]) ;
puts("") ;
}
}
return 0 ;
}
HDU 4622 多校第三场1002 后缀自动机的更多相关文章
- hdu 4888 2014多校第三场1002 Redraw Beautiful Drawings 网络流
思路:一開始以为是高斯消元什么的.想让队友搞,结果队友说不好搞,可能是网络流.我恍然,思路立刻就有了. 我们建一个二部图.左边是行,右边是列,建个源点与行建边,容量是该行的和.列与新建的汇点建边.容量 ...
- HDU 4628 多校第三场1008 dp
这题就没什么好说的了.直接枚举2 ^ 16 的状态,用1表示拿这位,0表示不拿,每次判断是否可以这么拿. #include <iostream> #include <cstdio&g ...
- HDU暑假多校第三场H.Monster Hunter
一.题意 给定一个树状地图,每个树节点上有一只怪物,打死一只怪物的过程中将会消耗A点HP,打死之后将会获得B点HP.因为树状结构,所以每只怪物必须先打死父节点的怪兽之后在打死子节点的怪物.现在,给定每 ...
- 2018 HDU多校第三场赛后补题
2018 HDU多校第三场赛后补题 从易到难来写吧,其中题意有些直接摘了Claris的,数据范围是就不标了. 如果需要可以去hdu题库里找.题号是6319 - 6331. L. Visual Cube ...
- 牛客多校第三场 F Planting Trees
牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...
- 牛客多校第三场 G Removing Stones(分治+线段树)
牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...
- 2019 牛客暑期多校 第三场 F Planting Trees (单调队列+尺取)
题目:https://ac.nowcoder.com/acm/contest/883/F 题意:求一个矩阵最大面积,这个矩阵的要求是矩阵内最小值与最大值差值<=m 思路:首先我们仔细观察范围,我 ...
- 2015 多校赛 第三场 1002 (hdu 5317)
Description Mr. Hdu is interested in Greatest Common Divisor (GCD). He wants to find more and more i ...
- hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...
随机推荐
- SGU 156. Strange Graph(欧拉路)
时间限制:0.25s 空间限制:6M 题目描述 让我们想象一个无向图G=<V,E>.如果边(u,v)在边集E中,那么我们就说两个顶点u和v是邻接点.在这种情况下,我们也说u是v的一个邻接点 ...
- iOS 数据持久性存储-属性列表
iOS上常用四种数据存取方法有: 1.属性列表 2.对象归档 3.iOS的嵌入式关系数据库(SQLite3) 4.苹果公司提供持久性共聚Core Data 由于苹果公司的沙盒机制,每个应用程序都有自己 ...
- 本大神教你用PHP把文本内容转换成16进制数字,进行加密
<?php $a="杨波"; $b = bin2hex($a); echo $a."<br />"; $c = pack("H*&q ...
- jQuery api 学习笔记(1)
之前自己的jquery知识库一直停留在1.4的版本,而目前jquery的版本已经更新到了1.10.2了,前天看到1.10中css()竟然扩充了那么多用法,这2天就迫不及待的更新一下自己的jquer ...
- python路径相关
import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 将当 ...
- bzoj1855: [Scoi2010]股票交易
Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...
- oracle 查询dblink的方法
oracle 查询dblink的方法: SYSDBA登录, sys登录 SELECT * FROM SYS.link$;
- Jenkins安装入门
这是一次兴奋之旅哈..说不定用得着呢~~~:) 嘿嘿.. 安装很简单,JDK,MAVEN(如果),YUM或RPM包安装JENKINS(因为好像YUM安装好慢,不如RPM下载安装) 参考URL: htt ...
- sql server 发布时提示'dbo.sysmergepublications'无效的解决办法
对数据库进行数据库复制.订阅时经常会出现各种奇怪的问题 如果你对数据库进行多次发布.删除发布操作时可能会提示“dbo.sysmergepublications”无效的问题, 可以使用以下方法解决: U ...
- sicp第1章
牛顿迭代法求平方: (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) ...