题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5030

题意:给出一个长度为n的串S,将S分成最多K个子串S1,S2,……Sk(k<=K)。选出每个子串Si(1<=i<=k)的最大子串SSi。最后使得k个SSi的最大值最小。

思路:首先用后缀数组求出所有子串。二分答案串,判定是否存在一种分法满足要求。对于答案串A,设A起始位置所组成的后缀排名为t,在排名为[t+1,n]的后缀中截取子串S[Li,Ri],使得Ri<n(下标1到n),且该子串和A具有大于0的公共前缀(若这些之中存在与A的公共前缀为0的后缀则A不成立),那么这样的子串有啥性质呢?他们的性质就是他们加上他们在原串中的下一个字母后组成的串都比答案串A大(很显然吧。因为我们找的都是排名在A之后的后缀截取的)。那么,理论上来讲,这样的串一出现,我们就要截取一下,因为他们不能和后面一个字母挨在一起。

但是,看下面的情况,比如所有这样的串为:[4,10],[5,15],[5,20],[6,11],[6,25],[30,40],首先我们要在10的位置截开,这样[4,10]就不会跟后面一个字母挨在一起了,然后随着这一截开,[5,15],[5,20],[6,11],[6,25]这些串都被分成两段了,所以他们不用再被截开了,之后再从40位置截开。最后截了两次分成了三段。

const int INF=1000000005;
const int N=111111; int r[N],sa[N],wa[N],wb[N],wd[N],rank[N],h[N]; int cmp(int *r,int a,int b,int len)
{
return r[a]==r[b]&&r[a+len]==r[b+len];
} void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
FOR0(i,m) wd[i]=0;
FOR0(i,n) wd[x[i]=r[i]]++;
FOR1(i,m-1) wd[i]+=wd[i-1];
for(i=n-1;i>=0;i--) sa[--wd[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p)
{
p=0;
for(i=n-j;i<=n-1;i++)y[p++]=i;
FOR0(i,n) if(sa[i]>=j) y[p++]=sa[i]-j;
FOR0(i,m) wd[i]=0;
FOR0(i,n) wd[x[i]]++;
FOR1(i,m-1) wd[i]+=wd[i-1];
for(i=n-1;i>=0;i--) sa[--wd[x[y[i]]]]=y[i];
t=x;x=y;y=t;p=1;x[sa[0]]=0;
FOR1(i,n-1) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
} void calHeight(int *r,int *sa,int n)
{
int i,j,k=0;
FOR1(i,n) rank[sa[i]]=i;
FOR0(i,n)
{
if(k) k--;
j=sa[rank[i]-1];
while(i+k<n&&j+k<n&&r[i+k]==r[j+k]) k++;
h[rank[i]]=k;
}
} char s[N];
int K;
int n; i64 f[N]; vector<pii > V,p; int cal()
{
if(SZ(V)==0) return 0;
sort(all(V));
int minR=INF;
p.clear();
int i;
for(i=SZ(V)-1;i>=0;i--)
{
if(minR<=V[i].second) continue;
minR=V[i].second;
p.pb(V[i]);
}
int ans=0,last=-1;
sort(all(p));
for(i=0;i<SZ(p);i++)
{
if(last>=p[i].first) continue;
ans++;
last=p[i].second;
}
return ans;
} int ansL,ansR; int ok(i64 M)
{
int t=lower_bound(f+1,f+n+1,M)-f;
int L=sa[t];
int len=h[t]+M-f[t-1]; ansL=L;
ansR=L+len-1; V.clear();
if(L+len<n) V.pb(MP(L,L+len-1));
int i;
for(i=t+1;i<=n;i++)
{
len=min(len,h[i]);
if(!len) return 0;
if(sa[i]+len<n) V.pb(MP(sa[i],sa[i]+len-1));
}
return cal()<K;
} void print()
{
int i;
for(i=ansL;i<=ansR;i++) putchar(s[i]); puts("");
}
int main()
{ while(scanf("%d",&K)!=-1)
{
if(!K) break;
scanf("%s",s);
n=strlen(s);
int i;
for(i=0;i<n;i++) r[i]=s[i]-'a'+1;
r[n]=0;
da(r,sa,n+1,30);
calHeight(r,sa,n); for(i=1;i<=n;i++) f[i]=f[i-1]+n-sa[i]-h[i]; i64 low=1,high=f[n],ans=f[n];
while(low<=high)
{
i64 M=(low+high)>>1; if(ok(M)) ans=min(ans,M),high=M-1;
else low=M+1;
}
ok(ans);
print();
}
}

HDU 5030 Rabbit's String的更多相关文章

  1. hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分法)

    Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  2. 【HDU 5030】Rabbit's String (二分+后缀数组)

    Rabbit's String Problem Description Long long ago, there lived a lot of rabbits in the forest. One d ...

  3. HDU 5842 Lweb and String(Lweb与字符串)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  4. hdu 4850 Wow! Such String! 欧拉回路

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4080264.html 题目链接:hdu 4850 Wow! Such String! 欧拉回 ...

  5. hdu 3553 Just a String (后缀数组)

    hdu 3553 Just a String (后缀数组) 题意:很简单,问一个字符串的第k大的子串是谁. 解题思路:后缀数组.先预处理一遍,把能算的都算出来.将后缀按sa排序,假如我们知道答案在那个 ...

  6. hdu 4778 Rabbit Kingdom(减少国家)

    题目链接:hdu 4778 Rabbit Kingdom 题目大意:Alice和Bob玩游戏,有一个炉子.能够将S个同样颜色的宝石换成一个魔法石.如今有B个包,每一个包里有若干个宝石,给出宝石的颜色. ...

  7. HDU 4777 Rabbit Kingdom(树状数组)

    HDU 4777 Rabbit Kingdom 题目链接 题意:给定一些序列.每次询问一个区间,求出这个区间和其它数字都互质的数的个数 #include <cstdio> #include ...

  8. HDU 4850 Wow! Such String!(欧拉道路)

    HDU 4850 Wow! Such String! 题目链接 题意:求50W内的字符串.要求长度大于等于4的子串,仅仅出现一次 思路:须要推理.考虑4个字母的字符串,一共同拥有26^4种,这些由这些 ...

  9. HDU 4777 Rabbit Kingdom (2013杭州赛区1008题,预处理,树状数组)

    Rabbit Kingdom Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

随机推荐

  1. 不同版本mysql语句不兼容原因

    一般是sql_mode不相同,可以认为规则不一致.(语法的变化非常小,一般可以忽略) 如果想要导入不同版本的数据.可以: 手动处理一些导入错误或者采用其他的办法. 或者 修改sql_mode.具体修改 ...

  2. java父类转子类的一个方法

    一般子类可以转父类.但父类转子类就会报cast error. 使用jsonobject 思想:先把父类转jsonstring 再把jsonstring转子类.剩余的子类值可以设定进去. import ...

  3. javascript和jquery中获取列表的索引

    网页中的图片预览一般都需要获取图片列表的索引,或则图片对应的标签的索引,以此达到点击相应的标签获取索引,显示相应的图片 列表有很多种表达的方式,一种是 <ul> <li>苹果& ...

  4. python中遇到的各种问题

    一 编码问题 python的默认编码是ascii码,可以修改为utf-8 在python\Lib\site-packages\下添加一个文件sitecustomize.py 内容是 import sy ...

  5. Linux Centos 上一些常用的命令

    1.查看端口被哪个进程占用 netstat -lnp | grep <端口号> 2.查看某个进程号详细信息 ps <进程号> 3.检查指定服务是否开启(例如 telnet) c ...

  6. protocolbuffe

    protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台.google 提供了多种语言的实现:java.c#.c++.go 和 python,每一种实 ...

  7. Java常用快捷键

    Ctrl+M 最大化当前的Edit或View (再按则反之) Crl+k:查找下一处 Ctrl+Shift+O 导包 Ctrl+W 关闭当前EditerCtrl+shift+W 关闭所有当前页 Ctr ...

  8. [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断

    参考:http://blog.csdn.net/beyondhaven/article/details/4204345 参考:http://blog.csdn.net/joeblackzqq/arti ...

  9. JAVA字段的初始化规律

    JAVA字段的初始化规律 1.类的构造方法 (1)“构造方法”,也称为“构造函数”,当创建一个对象时,它的构造方法会被自动调用.构造方法与类名相同,没有返回值. (2)如果类没有定义构造函数,Java ...

  10. MySQL 及 SQL 注入

    如果您通过网页获取用户输入的数据并将其插入一个MySQL数据库,那么就有可能发生SQL注入安全的问题. 本章节将为大家介绍如何防止SQL注入,并通过脚本来过滤SQL中注入的字符. 所谓SQL注入,就是 ...