主题: problem-6988(dingbacode.com) )。
赋予一个字符串和每个字符的权重,求出本质不同的所有子字符串中第k个小字符串的权重。 字符串的权重是字符权重之和。
意识到必须考虑所有子串的情况,不能从中选择第k个小答案。 因此,为了得到结果,考虑用数据结构保存,或者迅速列举所有情况。 因为知道所有后缀的所有前缀都是所有子字符串的情况,所以通过枚举每个后缀的所有前缀可以期待结果。 但是,暴力列举绝对会超时,届时需要用于处理的数据结构。
首先要明确一点,从所有情况中选择第k个小答案的做法会超时。 由于情况非常多,各情况之间的大小关系不明确,所以要得到排序后的所有子序列的大小关系非常困难,需要花费时间。 注意到问题是输出结果这个唯一的数字,每个后缀的前缀的权重和长度都满足单调的关系,直接将答案平分列举,试图验证其正确性。
以下,考虑如何二分,确定下界为1,上界为原来的总串。 每次都计算中值mid,判断答案是在mid之前还是之后。 在答案为mid情况下,子串的权重小于不大于mid的数量的k意味着mid小; 否则,表示答案=mid,进一步缩小范围。
然后,求出子列的权重如何小于等于mid的数量。 对于每个后缀,前缀越长,权重就越大,因此可以在另二分钟内找到第一个权重大于mid的前缀。 假设当前后缀的开始位置为I,并且此后缀的第一个权重大于mid的前缀的末尾为j,则此后缀对当前枚举的答案的贡献前缀数为[j-1]-I1。 但是,请注意不同后缀的前缀可能是相同的,知道不同后缀的公共前缀(LCP )并加重回答。 到此为止可以用后缀数组处理。 通过按后缀的顺序列举后缀,可以通过height数组了解当前字符串和前一个字符串的重复前缀。 就这样减法就行了。
有关什么是后缀数组的信息,请参见此-后缀数组详细信息- chr ety-Blogs.com
很会说话,居然能让我看会议。
代码:
#includeiostream
using namespace std;
typedef long long int ll;
ll ran[100005]、sec[100005]、sa[100005]、t[100005]、hei[100005];
ll val[26],sum[100005];
char s[100005];
voidGetsa(lln )。
{
ll num,I,len,cnt;
num=26;
for(I=0; i=100000; I ) t(I )=0;
for(I=1; i=n; I ) ran(I )=s(I-1 )-a ) 1,t ) ran ) );
for(I=1; i=num; I ) t(I )=t(I-1 );
for(I=n; i=1; I----sa[t[ran[I]]----]=I;
for(len=1; len=n; len=1)
{
cnt=0;
for(I=n-len1; i=n; I ) sec[ cnt]=i;
for(I=1; i=n; I ) if(sa[I]len ) sec[ cnt]=sa[i] - len;
for(I=0; i=num; I ) t(I )=0;
for(I=1; i=n; I ) t[ran[i]];
for(I=1; i=num; I ) t(I )=t(I-1 );
for(I=n; i=1; I----sa[t[ran[sec[I]]--]=sec[I],sec[i]=ran[i];
ran[sa[1]]=1; cnt=1;
for(I=2; i=n; I )
ran [ sa [ I ]=[ sec [ sa [ I ]==sec [ sa [ I-1 ] ] sec [ sa [ I ] len ]==sec [ sa [ I-1 ] len ]? cnt : cnt;
if(CNT==n ) break;
num=cnt;
}
}
语音获取(lln ) )。
{
ll i,j,k;
k=0;
for(I=1; i=n; I )
{
if(k ) k----;
j=sa[ran[i] - 1];
while(Ik=njk=ns[I-1k]==s[j-1k] ) k;
hei[ran[i]]=k;
}
}
llcheck(llx,ll n ) ) ) ) ) ) ) llcheck(llx,ll n ) ) ) ) ) ) )。
{
ll ans=0,I;
ll,r,mid,add;
for(I=1; i=n; I )
{
l=sa[i]; r=n 1; add=-1;
wile(LR ) )。
{
mid=(LR ) 1;
if(sum[mid]-sum[sa[I]-1]=x ) l=mid 1,add=mid;
else r=mid;
}
if (添加!=-1 )
{
ans =add - sa[i] 1;
ans -=add - sa[i] 1 hei[i]? hei[i] : add - sa[i] 1;
}
}
返回ans;
}
int main () )
{
LTT,n,I,k,ans,l,r,mid;
cin tt;
while(TT----
{
scanf('%lld%lld )、n、k );
scanf('%s ',s );
for(I=0; i 26; I ) scanf('%lld ',val[i];
GETSA(n;
GETH(n;
sum[0]=0;
for(I=1; i=n; I ) sum[i]=val[s[i - 1] - 'a'] sum[i - 1];
l=1; r=sum[n] 1; ans=-1;
wile(LR ) )。
{
mid=(LR ) 1;
if(check(mid,n )=k ) r=mid,ans=mid;
else l=mid 1;
}
printf(%lld(n ),ans );
}
}