2013 多校第九场 hdu 4691 Front compression(暴力 + 剪枝 OR 后缀数组)
2013-08-20 20:28
411 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4691题目大意:输入一组字符串,对于输入的每一个字符串,输出一个数字加一个空格加一个字符串加一个回车,数字为它和上一个输入的字符串的公共前缀的长度,字符串为未匹配的字符串,空串的话长度也为1,最后输出两个数,分别是输入的所有的长度和和输出的长度和,空格和回车都算一个。思路:暴力枚举前缀,然后TLE,然后加了一个剪枝,就是:如果前一个字符串的起始位置和现在这个一样,那么就直接算出来。然后就这样神奇的 3000ms 飘过了。。 只能说测试数据里这样的数据太多了。。 = =这题的正解应该是后缀数组,今天花了一天去学了这个东西。 现在发现这题应该是后缀数组里很基础的了,前后两者的重叠部分的长度就是 min( lcp(pre_a,a), b - a ,pre_b - pre_a),当pre_a == a 是 lcp 里需要特判,然后 rank[ a ] > rank[ pre_a ] 交换一下,使 a 的rank 在前面,rmq 查询的区间应该是 rmq(rank[ a ] + 1,rank[ pre_a ]),注意,这里要+1,因为 height[ i ] 表示的是后缀 sa[i ] 和sa[ i - 1] 的公共前缀。暴力代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef __int64 lld; const int MAXN = 100011; char str[MAXN]; int main() { while(~scanf("%s",str)) { int n; scanf("%d",&n); int pre_a = -1 ,pre_b = -1; int a,b; lld ans1 = 0,ans2 = 0; for(int i = 0;i<n;i++) { scanf("%d%d",&a,&b); ans1 += (b-a+1); if(a==pre_a) { if(b>pre_b) { ans2 += b - pre_b; int len = pre_b - a; if(len == 0 ) ans2 ++ ; while(len) { ans2++; len /= 10; } ans2 += 2; } else { int len = b - a; if(len ==0) ans2 ++ ; while(len) { ans2 ++ ; len /= 10; } ans2 += 2; } } else { int dis = 0; for(int i = a,j = pre_a;i<b&&j<pre_b;i++,j++) if(str[i]==str[j]) dis++; else break; int len = dis; if(len == 0 ) ans2 ++ ; while(len) { ans2++; len /= 10; } ans2 += b - a - dis + 2; } pre_a = a; pre_b = b; } printf("%I64d %I64d\n",ans1,ans2); } return 0; }后缀数组代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef __int64 lld; const int MAXN = 111111 ; int t[MAXN],t2[MAXN],sa[MAXN],c[222]; char str[MAXN]; void build_sa(int n,int m) { int *x = t,*y = t2; for(int i = 0;i<m;i++) c[i] = 0; for(int i = 0;i<n;i++) c[x[i] = str[i]] ++; for(int i = 1;i<m;i++) c[i] += c[i - 1]; for(int i = n - 1;i>=0;i--) sa[--c[x[i]]] = i; for(int k = 1;k<n;k <<= 1) { int p = 0; for(int i = n - k ;i<n;i++) y[p++] = i; for(int i = 0;i<n;i++) if(sa[i] >= k) y[p++] = sa[i] - k; for(int i = 0;i<m;i++) c[i] = 0; for(int i = 0;i<n;i++) c[x[y[i]]] ++ ; for(int i = 1;i<m;i++) c[i] += c[i - 1]; for(int i = n - 1;i>=0;i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y); x[sa[0]] = 0; p = 1; for(int i = 1;i<n;i++) x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++; if(p>=n) break; m = p; } } int rank[MAXN],height[MAXN]; void get_height(int n) { for(int i = 1;i<=n;i++) rank[sa[i]] = i; int k = 0; for(int i = 0;i<n;i++) { if(k) k--; int j = sa[rank[i] - 1]; while(str[i + k] == str[j + k]) k ++; height[rank[i]] = k; } // for(int i = 1;i<=n;i++) //printf("i = %d,height[i] = %d,sa = %d\n",i,height[i],sa[i]); } int d[MAXN][111]; void init_rmq(int n) { for(int i = 1;i<=n;i++) d[i][0] = height[i]; for(int j = 1;(1<<j) <= n;j++) for(int i = 1;i + (1<<j) - 1 <=n;i++) { d[i][j] = min(d[i][j - 1] ,d[ i + (1<<(j - 1))][ j - 1 ]); } } int rmq(int a,int b) { int k = 0; while((1<<(k+1)) < (b - a + 1)) k++; return min(d[a][k],d[b - (1<<k) + 1][k]); } int lcp(int a,int b,int n) { if(a == b) return n - a ; a = rank[a],b = rank[b]; if(a>b) swap(a,b); return rmq(a + 1 , b); } int main() { while(~scanf("%s",str)) { int len = strlen(str); build_sa(len+1,128); get_height(len); init_rmq(len); int q; scanf("%d",&q); int a,b; scanf("%d%d",&a,&b); lld ans1 = b - a + 1; lld ans2 = 1 + b - a + 2; q--; int pre_a = a,pre_b = b; while(q--) { scanf("%d%d",&a,&b); ans1 += b - a + 1; //printf("lcp = %d\n",lcp(pre_a,a,len)); int tt = min(lcp(pre_a,a,len),min(b - a,pre_b - pre_a)); int tmp = tt; if(tmp == 0) ans2 ++; while(tmp) { ans2 ++; tmp /= 10; } ans2 += b - a - tt + 2; pre_a = a; pre_b = b; } printf("%I64d %I64d\n",ans1,ans2); } return 0; }
相关文章推荐
- HDU 4691(多校第九场1006) 后缀数组
- HDU 4691(多校第九场1006) 后缀数组
- HDU 4691 Front compression (2013多校9 1006题 后缀数组)
- 2013 多校第九场 hdu 4699 Editor(vector OR splay tree)
- 2013 多校第九场 hdu 4686 Arc of Dream(矩阵乘法或者直接推公式)
- hdu 4699 2个栈维护 or 伸展树 (2013多校联合)
- 2013 多校第九场 hdu 4690 EBCDIC(打表)
- 2013 多校第九场 hdu 4705 Y(枚举 + 树上的计数)
- 2013 多校第九场 hdu 4704 Sum(2的幂次方取模)
- HDU 4876 ZCC loves cards (2014多校联合训练第二场1005) 解题报告(暴力+剪枝)
- hdu 4876 ZCC loves cards 多校第二场 暴力+剪枝
- HDU 4691 Front compression (2013 多校联合9 1006)
- 2013 多校第九场 hdu 4696 Answers(纯YY )
- 2013 Multi-University Training Contest 9(hdu 4686 - 4691)dp(好)+矩阵快速幂+一般图匹配带花树+后缀数组
- HDU 4618 Palindrome Sub-Array (2013多校2 1008 暴力)
- HDU 4619 Warm up 2(2013多校2 1009 二分匹配)
- 2013 多校联合2 D Vases and Flowers (hdu 4614)
- HDU 4671 Backup Plan (2013多校7 1006题 构造)
- HDU 4671 Backup Plan (2013多校联合7 1006)
- HDU 5918 Sequence I【暴力+剪枝】(2016中国大学生程序设计竞赛(长春)H题)