[JSOI2015]串分割 解题报告
题目背景
JYY 每天都会在地铁上度过很长的时间。
为了打发时间,JYY 随手写下了一个很长的环形的数字字符串,并且陷入了沉思。
题目描述
JYY 写下了一个长度为 \(N\) 的,仅包含 1,2,……,9 这 \(9\) 种不同字符的环形字符串 \(S\)。JYY 希望把 \(S\) 进行 \(K\) 次切割,并分成 \(K\) 个非空的子串。对于每一个子串,由于其仅包含数字,我们可以将其看成一个十进制数——因此
经过 \(K\) 次切割,JYY 可以得到 \(K\) 个不同的十进制数。JYY 希望他得到的这 \(K\) 个数中,最大的那一个尽量小。
输入格式
第一行包含两个整数 \(N\) 和 \(K\)。
第二行包含一个长度为 \(N\) 的字符串 \(S\)。
输出格式
输出一行包含一个正整数,表示最佳分割方案中,JYY 所得到的那 \(K\) 个数中,最大的那一个。
样例 #1
样例输入 #1
4 2
4321
样例输出 #1
32
提示
对于 \(100\%\) 的数据,\(3\leq N\leq 2\times 10^5\),\(2\leq K\leq N\)。
思路
由于要划分最大的最小(二分!)
因此我们划分的段们长度尽可能平均
我们考虑二分最大的那一节的开头
要求后缀数组\(rk\)
因为最大的要最小,所以我们根据\(rk\)值来二分!!
显然要使最大的那一节的开头\(rk\)尽可能小
这样答案就满足单调性啦(。・∀・)ノ゙
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=4e5+2;
char s[N];
ll rk[N],sa[N],c[N],x[N],y[N],tot,hei[N],n,k,len;
void getsa(int m){//后缀数组
for(ll i=1;i<=m;i++)c[i]=0;
for(ll i=1;i<=n;i++)c[x[i]=s[i]]++;
for(ll i=2;i<=m;i++)c[i]+=c[i-1];
for(ll i=n;i>=1;i--)sa[c[x[i]]--]=i;
for(ll k=1;k<=n;k<<=1){
ll tot=0;
for(ll i=n-k+1;i<=n;i++)y[++tot]=i;
for(ll i=1;i<=n;i++){
if(sa[i]>k)y[++tot]=sa[i]-k;
}
for(ll i=1;i<=m;i++)c[i]=0;
for(ll i=1;i<=n;i++)c[x[i]]++;
for(ll i=2;i<=m;i++)c[i]+=c[i-1];
for(ll i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i];
swap(x,y);
x[sa[1]]=1,tot=1;
for(ll i=2;i<=n;i++){
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?tot:++tot;
}
if(tot==n)break;
m=tot;
}
}
void gethei(){//hei[i]:排名为i和排名前一个的lcp
for(ll i=1;i<=n;i++)rk[sa[i]]=i;
for(ll i=1,k=0;i<=n;i++){
if(rk[i]==1)continue;
if(k)k--;
ll j=sa[rk[i]-1];//排名前面一个
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
hei[rk[i]]=k;
}
}
bool check(ll mid,ll m){
bool ok=0;
for(ll i=1;i<=len;i++){
ll cnt=0;//length长度
for(ll j=1;j<=k;j++){//k段
ll p=(i+cnt-1)%m+1;
if(rk[p]<=mid) cnt+=len;//数小的长度大→最大的尽量小
else cnt+=len-1;
}
ok|=(cnt>=m);
}
return ok;
}
int main(){
scanf("%lld%lld%s",&n,&k,s+1);
len=(n-1)/k+1;//长度要平均
for(ll i=1;i<=n;i++){
s[i+n]=s[i];
}
n<<=1;//破环为链
getsa(127);
gethei();
ll l=1,r=n;
while(l<r){
ll mid=(l+r)>>1;
if(check(mid,n>>1)) r=mid;
else l=mid+1;
}
for(ll i=1;i<=len;i++){
printf("%c",s[sa[l]+i-1]);
}
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。

浙公网安备 33010602011771号