标签:
题目链接:HDU 5769
题面:
2 a abc b bbb
Case #1: 3 Case #2: 3HintIn first case, all distinct substrings containing at least one a: a, ab, abc. In second case, all distinct substrings containing at least one b: b, bb, bbb.
题意:
给定一个字符串,问该字符串中包含某一字符的不重复子串的数量。
解题:
后缀数组的大致原理是懂的,自己写是写不出来的,勉强算是会用吧。这题可以先看一下,如何求某字符串的不重复子串的数量。
ans=sigma(length-sa[i]-height[i]),如何理解呢,sa[i]表示的是字典序排名为i的后缀,它的起始位置,length-sa[i],即为排名i的后缀的长度,height[i],是排名为i的串和它之前那个串的公共前缀长度,故length-sa[i]-height[i],(减去和字典序前一个的公共前缀)即为不重复子串数量。
而针对这题,需要包含特殊字符,故预先找到各个后缀中,离该后缀左侧最近的特殊字符的位置,综合该后缀不重复子串长度,取得最值。
代码:
#include <iostream> #include <string> #include <cstring> #include <cstdio> #define rep(i,n) for(int i = 0;i < n; i++) #define sz 100005 #define LL long long using namespace std; char ori[sz]; int rk[sz],sa[sz],height[sz],w[sz],wa[sz],res[sz],pos[sz]; int min(int a,int b) { return a<b?a:b; } int max(int a,int b) { return a>b?a:b; } void getSa (int len,int up) { int *k = rk,*id = height,*r = res, *cnt = wa; rep(i,up) cnt[i] = 0; rep(i,len) cnt[k[i] = w[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) sa[--cnt[k[i]]] = i; int d = 1,p = 0; while(p < len) { for(int i = len - d; i < len; i++) id[p++] = i; rep(i,len) if(sa[i] >= d) id[p++] = sa[i] - d; rep(i,len) r[i] = k[id[i]]; rep(i,up) cnt[i] = 0; rep(i,len) cnt[r[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) sa[--cnt[r[i]]] = id[i]; swap(k,r); p = 0; k[sa[0]] = p++; rep(i,len-1) { if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]] == r[sa[i+1]]&& r[sa[i]+d] == r[sa[i+1]+d]) k[sa[i+1]] = p - 1; else k[sa[i+1]] = p++; } if(p >= len) return ; d *= 2,up = p, p = 0; } } void getHeight(int len) { rep(i,len) rk[sa[i]] = i; height[0] = 0; for(int i = 0,p = 0; i < len - 1; i++) { int j = sa[rk[i]-1]; while(i+p < len&& j+p < len&& w[i+p] == w[j+p]) p++; height[rk[i]] = p; p = max(0,p - 1); } } int getSuffix(char s[]) { int len = strlen(s),up = 0; for(int i = 0; i < len; i++) { w[i] = s[i]; up = max(up,w[i]); } w[len++] = 0; getSa(len,up+1); getHeight(len); return len; } int main() { int t,l; char c; LL ans; scanf("%d",&t); for(int ix=1;ix<=t;ix++) { ans=0; scanf(" %c",&c); scanf("%s",ori); getSuffix(ori); l=strlen(ori); int j; for(pos[l]=l,j=l-1;j>=0;j--) if(ori[j]==c) pos[j]=j; else pos[j]=pos[j+1]; for(int i=1;i<=l;i++) ans=ans+min(l-sa[i]-height[i],l-pos[sa[i]]); printf("Case #%d: %lld\n",ix,ans); } return 0; }
标签:
原文地址:http://blog.csdn.net/david_jett/article/details/52072824