HDU 5030 Rabbit's String 后缀数组
2014-09-24 16:56
330 查看
【题目大意】
有一个只有小写字母的字符串,你要把其分成不超过k个不重叠的连续子串。对于每个子串,求其字典序最大的子串(为了与前者区分,我们称为子串2)。所有子串2,有一个字典序最大的串,我们称为目标串。问,怎么分,使得目标串字典序最小,输出这个目标串。
【思路】
很有意思的一题。首先,目标串一定是原串的一个子串。那么可以考虑去二分目标串(即二分所有子串)。
这里有个问题,怎么确定原串的第k大串是什么?这个问题是HDU 5008的简化版,我在以前博客中有写。
现在剩下的问题,就是对于确定串S(这个串是原串的子串),使得它成为目标串,至少把原串分为几部分?
这里可以贪心求解,举个例子:使“ba”成为“bbaa”的目标串,至少分几部分。
记re[i]表示,以原串的第i个字符做起点,求一个最大re[i],使得原串的子串[i,re[i]]字典序小于等于目标串“ba”。
bbaa的re[]为
下标:0 1 2 3
re[ ]:0 2 3 3
我们从左到右,贪心地加字符,能加就加,不能加就隔断,最后有几段,就是分几部分。具体怎么贪心,看下面代码。
ans = 0;
temp = -1;
for(i = 0; i < n; i ++)
{
if(re[i] < i)
return INF;
if(i > temp)
{
ans++;
temp = re[i];
}
else
temp = min(temp, re[i]);
}
return ans;
有一个只有小写字母的字符串,你要把其分成不超过k个不重叠的连续子串。对于每个子串,求其字典序最大的子串(为了与前者区分,我们称为子串2)。所有子串2,有一个字典序最大的串,我们称为目标串。问,怎么分,使得目标串字典序最小,输出这个目标串。
【思路】
很有意思的一题。首先,目标串一定是原串的一个子串。那么可以考虑去二分目标串(即二分所有子串)。
这里有个问题,怎么确定原串的第k大串是什么?这个问题是HDU 5008的简化版,我在以前博客中有写。
现在剩下的问题,就是对于确定串S(这个串是原串的子串),使得它成为目标串,至少把原串分为几部分?
这里可以贪心求解,举个例子:使“ba”成为“bbaa”的目标串,至少分几部分。
记re[i]表示,以原串的第i个字符做起点,求一个最大re[i],使得原串的子串[i,re[i]]字典序小于等于目标串“ba”。
bbaa的re[]为
下标:0 1 2 3
re[ ]:0 2 3 3
我们从左到右,贪心地加字符,能加就加,不能加就隔断,最后有几段,就是分几部分。具体怎么贪心,看下面代码。
ans = 0;
temp = -1;
for(i = 0; i < n; i ++)
{
if(re[i] < i)
return INF;
if(i > temp)
{
ans++;
temp = re[i];
}
else
temp = min(temp, re[i]);
}
return ans;
//#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<cmath> #include<cctype> #include<string> #include<algorithm> #include<iostream> #include<ctime> #include<map> #include<set> using namespace std; #define MP(x,y) make_pair((x),(y)) #define PB(x) push_back(x) typedef __int64 LL; //typedef unsigned __int64 ULL; /* ****************** */ const int INF = 100011122; const double INFF = 1e100; const double eps = 1e-8; const int mod = 1000000007; const int NN = 100010; const int MM = 5000010; /* ****************** */ char ss[NN]; int a[NN], re[NN]; LL sum[NN]; int wa[NN],wb[NN],wv[NN],wss[NN],sa[NN]; int rank[NN],height[NN]; int rmq[NN][20],long2[NN]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} //r[n-1]==0; void da(int *r,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++)wss[i]=0; for(i=0;i<n;i++)wss[x[i]=r[i]]++; for(i=1;i<m;i++)wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--)sa[--wss[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++)y[p++]=i; for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; for(i=0;i<n;i++)wv[i]=x[y[i]]; for(i=0;i<m;i++)wss[i]=0; for(i=0;i<n;i++)wss[wv[i]]++; for(i=1;i<m;i++)wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--)sa[--wss[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } void calheight(int *r,int n) { int i,j,k=0; for(i=1;i<=n;i++)rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); return; } void initRMQ(int n) { int i,j,en; long2[1]=0; for(i=2;i<=n;i++) { long2[i]=long2[i-1]+(i==(i&(-i))); } for(i=1;i<=n;i++)rmq[i][0]=height[i]; for(j=1;j<=long2 ;j++) { en=n+1-(1<<j); for(i=1;i<=en;i++) rmq[i][j]=min(rmq[i][j-1],rmq[ i+(1<<(j-1)) ][j-1]); } } int lcp(int i,int j) { i=rank[i],j=rank[j]; if(i>j)swap(i,j); i++; int k=long2[j-i+1]; int ans=min(rmq[i][k],rmq[ j+1-(1<<k) ][k]); return ans; } int solve(int st,int l,int len,int n) { int i, temp, ans; for(i = 0; i < n; i ++) { if(i==l) { re[i] = l + len - 1; continue; } temp = lcp(i, l); temp = min(temp, len); if(rank[i] < st) { if(temp == len) re[i] = i + temp - 1; else re[i] = n-1; } else { re[i] = i + temp - 1; } } ans = 0; temp = -1; for(i = 0; i < n; i ++) { if(re[i] < i) return INF; if(i > temp) { ans++; temp = re[i]; } else temp = min(temp, re[i]); } return ans; } int ok(LL k,int n) { if(k==0)return INF; int st = lower_bound(sum+1, sum+1+n, k) - sum; int l = sa[st]; int len = height[st] + k - sum[st-1]; return solve(st, l, len, n); } int main() { int n, k, i; LL l, r, mid; while(scanf("%d",&k)!=EOF) { if(k==0)break; scanf("%s", ss); n = strlen(ss); for(i = 0; i < n; i ++) { a[i] = ss[i]- 'a' +1; } a = 0; da(a,n+1,40); calheight(a,n); initRMQ(n); sum[0] = 0; for(i = 1; i <= n; i ++) { sum[i] = n - sa[i] - height[i]; sum[i] += sum[i-1]; } l = 0; r = sum ; while (l + 1 < r) { mid = (l + r)>>1; if(ok(mid,n) <= k) r = mid; else l = mid; } int st = lower_bound(sum+1, sum+1+n, r) - sum; int ll = sa[st]; int rr = ll + height[st] + r - sum[st-1] - 1; for(i = ll; i <= rr; i ++) { printf("%c",ss[i]); } puts(""); } return 0; }
相关文章推荐
- HDU 5030 Rabbit's String 后缀数组 二分 构造
- hdu 5030 Rabbit's String(后缀数组)
- HDU 6194 string string string [后缀数组]
- hdu 5030(2014广州网络赛)后缀数组+二分!
- HDU 3336 Count the string 后缀数组 或 (KMP + DP)
- HDU 6194 string string string :后缀数组+单调队列 | 后缀自动机
- 【后缀数组】 HDOJ 5030 Rabbit's String
- HDU 6194 string string string 后缀数组 + RMQ(线段树)
- string string string hdu 6194 (后缀数组做法)
- HDU - 3336 Count the string —— next数组求相同前缀后缀个数
- HDU 6194 String String String 后缀数组 正好出现K次的子串个数 CSU1632 至少出现2次的子串个数
- HDU 6194 string string string【后缀数组】
- hdu 5008 Boring String Problem 【后缀数组】
- HDU 5008 Boring String Problem 后缀数组 RMQ
- HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描
- HDU 4691 Front compression(后缀数组 LCA)
- Hdu 4080 & Poj 3882 Stammering Aliens (后缀数组 可重叠k次最长重复子串)
- HDU 4552 怪盗基德的挑战书 (后缀数组,4级)
- HDU 4552 怪盗基德的挑战书 (后缀数组,4级)
- HDU 3518 Boring counting(后缀数组 所有不重叠字串出现两次以上的次数)