JZOJ 3638. 【COCI2013】slasticar
来源:互联网 发布:网络教育法律专业 编辑:程序博客网 时间:2024/05/16 17:57
题目大意
给出一个长度为n的字符串A,接下来给出m个字符串,对于每个字符串B,用给出的方法去与A匹配:
1. 设B的长度为L,先与A的位置为1…L的一段进行匹配:先比较A[1]和B[1],接下来比较A[2]和B[2],直到比较完A[L]和B[L]全部匹配或出现一个不相同(即A[i]≠B[i])
2. 如果匹配失败,则匹配A的2..L+1和B的1..L,如果得不到长度为L的串(如:A的长度为12,L=6,则A[8..13]与B[1..6]匹配,但是13>12),则在A后面补’#’直到长度为L(即变成‘XXXX##’)。以此类推
3. 如果匹配成功或A[len(A)..len(A)+L-1]也匹配完,则退出匹配
求每个字符串匹配过程比较次数
样例:
【input】
7
1090901
4
87650
0901
109
090
【output】
7
10
3
4
解释:第一个字符串’87650’与A每一个片段都只比较了第1位就失败了;
第二个’0901’,先与’1090’比较1次,然后与’0909’比较4次(因为’090’是它们的公共前缀,则前3位都相同,但比较到第4位时’1’不等于’9’),然后与’9090’只比较了第1位,接着与’0901’匹配成功,比较了4次,总共1+4+1+4=10次
数据范围:
单个字符串B长度不超过
所有字符串B总长不超过
所有字符串均由数字0…9组成
限制:Time Limits:3s Memory Limits:256MB
正解
先考虑当前字符串B 不能匹配成功 的情况:
对于A[i..i+L-1],设它与B的LCP为lcp(i),则答案
那么我们可以枚举这个lcp,然后确定有多少段A[i..i+L-1]与B的LCP等于这个值
显然,把A[i..i+L-1]看成A的后缀Suffix(i)不会影响答案,因为现在考虑的是不能匹配成功的情况。
所以可以先给A的后缀排个序,然后从小到大枚举这个lcp,设它是j,就可以二分出一个区间l..r,使
这样时间复杂度就只有
O(Llogn)
再考虑字符串B 能匹配成功 的情况:
同样通过二分,可以确定lcp≥L的区间,在这个区间里找一个出现位置最前的(即sa的最小值),设它为p,则答案
当我们枚举lcp时,确定了一个区间l..r,那么只有sa[i]≤p [l≤i≤r]的才能统计入答案,打个主席树就好了
时间复杂度还是
O(Llogn)
代码
#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#define N 100005#define M 262205#define ll long longusing namespace std;int n,m,len;ll ans;struct TREE{ int tot; int l[M * 10], r[M * 10], sum[M * 10], root[M * 10]; void add(int L,int R,int v,int &cnt,int last) { cnt = ++tot; sum[cnt] = sum[last] + 1; if (L == R) return; int mid = (L + R) / 2; l[cnt] = l[last]; r[cnt] = r[last]; if (v <= mid) add(L,mid,v,l[cnt],l[last]); else add(mid + 1,R,v,r[cnt],r[last]); } int count(int L,int R,int v,int cnt,int last) { if (v >= R) return sum[last] - sum[cnt]; int mid = (L + R) / 2; if (v <= mid) return count(L,mid,v,l[cnt],l[last]); else return count(mid + 1,R,v,r[cnt],r[last]) + sum[l[last]] - sum[l[cnt]]; }}tree;int t[M];void add(int l,int r,int g,int v,int x){ t[x] = min(t[x],v); if (l == r) return ; int mid = (l + r) / 2; if (g <= mid) add(l,mid,g,v,x*2); else add(mid + 1,r,g,v,x * 2 + 1);}int getMin(int l,int r,int a,int b,int x){ if (l == a && r == b) return t[x]; int mid = (l + r) / 2; if (b <= mid) return getMin(l,mid,a,b,x * 2); if (a > mid) return getMin(mid + 1,r,a,b,x * 2 + 1); return min(getMin(l,mid,a,mid,x * 2),getMin(mid + 1,r,mid + 1,b,x * 2 + 1));}int s[N],v[N];int wa[N],wb[N];int le[N],ri[N];int sa[N],height[N];char ch[N],Str[N];bool cmp(int *r,int a,int b,int l){ return r[a] == r[b] && r[a + l] == r[b + l];}void getSA(){ memset(wa,255,sizeof(wa)); memset(wb,255,sizeof(wb)); int i,p,l,Max = '9' + 1; int *x = wa; int *y = wb; int *t; for (i = 0; i < n; i++) s[x[i] = ch[i]]++; for (i = 1; i < Max; i++) s[i] += s[i - 1]; for (i = n - 1; i >= 0; i--) sa[--s[x[i]]] = i; for (l = p = 1; p < n; Max = p,l *= 2) { for (p = 0, i = n - l; i < n; i++) y[p++] = i; for (i = 0; i < n; i++) if (sa[i] >= l) y[p++] = sa[i] - l; for (i = 0; i < Max; i++) s[i] = 0; for (i = 0; i < n; i++) s[v[i] = x[y[i]]]++; for (i = 1; i < Max; i++) s[i] += s[i - 1]; for (i = n - 1; i >= 0; i--) sa[--s[v[i]]] = y[i]; for (t = x, x = y, y = t, x[sa[0]] = 0, i = p = 1;i < n; i++) x[sa[i]] = cmp(y,sa[i - 1],sa[i],l)?p - 1:p++; }}int rank[N];void getHeight(){ int k = 0; for (int i = 0; i < n; i++) rank[sa[i]] = i; for (int i = 0; i < n; height[rank[i++]] = k) { k = k ? k - 1 : k; if (rank[i]) { for (int j = sa[rank[i] - 1]; ch[j + k] == ch[i + k]; k++); } }}int find(int l,int r,char c,int x){ if (l > r) return l; while (l < r) { int mid = (l + r) / 2; if (sa[mid] + x >= n || ch[sa[mid] + x] < c) l = mid + 1; else r = mid; } if (sa[l] + x >= n || ch[sa[l] + x] < c) return l + 1; else return l;}void getTree(){ memset(t,127,sizeof(t)); for (int i = 0; i < n; i++) { tree.add(0,n - 1,sa[i],tree.root[i + 1],tree.root[i]); add(0,n - 1,i,sa[i],1); }}int main(){ freopen("slasticar.in","r",stdin); freopen("slasticar.out","w",stdout); scanf("%d",&n); scanf("%s",ch); getSA(); getHeight(); getTree(); int T; scanf("%d",&T); while (T--) { scanf("%s",Str); len = strlen(Str); le[0] = 0; ri[0] = n - 1; for (m = 1; m <= len; m++) { le[m] = find(le[m - 1],ri[m - 1],Str[m - 1],m - 1); ri[m] = find(le[m],ri[m - 1],Str[m - 1] + 1,m - 1) - 1; if (le[m] > ri[m]) break; } ans = 0; if (m <= len) { for (int i = 0; i < m; i++) ans += ri[i] - le[i] + 1; printf("%lld\n",ans); } else { int last = getMin(0,n - 1,le[len],ri[len],1); for (int i = 0; i < len; i++) ans += tree.count(0,n - 1,last,tree.root[le[i]],tree.root[ri[i] + 1]); printf("%lld\n",ans); } }}
- JZOJ 3638. 【COCI2013】slasticar
- 【COCI2013】slasticar
- 【COCI2013】slasticar
- JZOJ 3637. 【COCI2013】linije
- jzoj 3637. 【COCI2013】linije
- JZOJ 3639 COCI2013 odasiljaci
- COCI2013 HIPERPROSTOR
- 【COCI2013】linije
- JZOJ3639 COCI2013 odasiljaci
- BZOJ3482: [COCI2013]hiperprostor
- COCI2013/2014#ROUND1完整解题报告
- 2017.5.21 COCI2013/2014 Contest#6
- [JZOJ 3424] 粉刷匠 && [JZOJ 4254] 集体照
- [JZOJ 1280]最大匹配
- [JZOJ 1281]旅行
- [1282 JZOJ]资源勘探
- [JZOJ 1283]排序统计
- JZOJ NOIP2014模拟 8.12
- Centos7虚拟机网络重启failed失败
- 283.Move Zeroes(C语言)
- pat L3-011. 直捣黄龙(dfs简单应用)
- 【JSON 注解】JSON循环引用2----JSON注解@JsonIgnoreProperties+JAVA关键字transient+后台对象与JSON数据的格式互相转化
- 31. Next Permutation
- JZOJ 3638. 【COCI2013】slasticar
- 洛谷P2051 [AHOI2009]中国象棋
- iTOP4412内核源码编译与安卓ndk应用编程
- 算法提高 01背包
- GCD浅析
- [BZOJ3572][Hnoi2014]世界树(虚树+树形dp+二分+lca)
- Tensorflow实战——利用多层感知机识别手写数字
- Android UI(编辑手机信息页面,中英文切换)
- ArcEngine开发过程中遇到axToolbarControl添加item变灰无法使用的解决方法总结