题意概要
称长度为 n n n 的字符串 ⟨ s 1 , s 2 , s 3 , … , s n ⟩ \langle s_1,s_2,s_3,\dots,s_n\rangle ⟨s1,s2,s3,…,sn⟩ 有一个 B o r d e r \tt{Border} Border 是 ⟨ s 1 , s 2 , s 3 , … , s d ⟩ ( 0 < d < n ) \langle s_1,s_2,s_3,\dots,s_d\rangle(0
称一个字符串为 B o r d e r l e s s \tt{Borderless} Borderless ,当且仅当其不存在 B o r d e r \tt{Border} Border 。
求字典序第 k k k 小的长度为 n n n 的 0 / 1 B o r d e r l e s s 0/1\;\tt{Borderless} 0/1Borderless 串。
数据范围与约定
k ≤ 1 0 18 , n ≤ 64 k\le 10^{18},n\le 64 k≤1018,n≤64 ,并且保证一定存在 k k k 个长度为 n n n 的 0 / 1 B o r d e r l e s s 0/1\;\tt{Borderless} 0/1Borderless 串。
考虑一位一位的确定(就像在 0 / 1 T r i e 0/1\tt{ Trie} 0/1Trie 上一样)。
用 f ( x ) f(x) f(x) 表示长度为 x x x 的 B o r d e r l e s s \tt{Borderless} Borderless 字符串的个数,可以考虑减去不合法的。
f ( x ) = 2 x − ∑ i = 1 ⌊ x 2 ⌋ 2 x − 2 i ⋅ f ( i ) f(x)=2^x-\sum_{i=1}^{\lfloor\frac{x}{2}\rfloor}2^{x-2i}\cdot f(i) f(x)=2x−i=1∑⌊2x⌋2x−2i⋅f(i)
枚举的是非法方案中的最短 B o r d e r \tt{Border} Border 长度为 i i i ,直接将其钦定在首尾,用 f ( i ) f(i) f(i) 确保没有更短的;剩下的 x − 2 i x-2i x−2i 个位置就随便填。注意到最短 B o r d e r \tt{Border} Border 是不会超过长度的一半的。
现在,由于我们已经确定了更高位,我们就得改变一下转移系数。注意:下面的 f ( x ) f(x) f(x) 都隐含着“前缀为 s ′ s' s′ ”的条件。
在已经填充了 d d d 位的前缀之后,假设 f ( i ) ( 0 < i ≤ d ) f(i)(0f(i)(0<i≤d) 表示前 i i i 位是否为 B o r d e r l e s s \tt{Borderless} Borderless ,是则为一,否则为零。那么可以这样转移(对于 d < x d
似乎就搞定了?复杂度是 O ( n 3 ) \mathcal O(n^3) O(n3) 的?
因我无评测环境,故此处贴出这篇博客中的代码,作为参考。
#include
#include
#include
typedef unsigned long long ull;
namespace bdc{
ull hr[64];
inline int borderless(ull str,int len){
ull a=0,b=0;
for(int i=0;i<len;++i){
a|=str&(1<<i);
b=(b<<1)|((str>>(len-i))&1);
if(a==b) return 0;
}
return 1;
}
inline void print(ull str,int len){
for(int i=0;i<len;++i) putchar('a'+((str>>i)&1));
}
inline ull calc(int n,ull k){
ull ans=0;
for(int i=0;i<n;++i){
hr[0]=1;
for(int j=1;j<=i;++j){
hr[j]=borderless(ans,j);
}
for(int j=i+1;j<n;++j){
hr[j]=0;
for(int k=0;k+k<=j-1;++k){
int v=std::max(i,k); // prefix that has been determined
if(k+v+1>j){ // if overlapped
int vt=k+v+1-j;
ull mask=(1ull<<vt)-1;
if((ans&mask) == ((ans>>(j-k))&mask)){
hr[j]+=hr[k]; // if can into border
}
}
else{
hr[j]+=hr[k]<<(j-k-v-1); // if not overlapped, then [border][len(xjbstr|NULLStr)=j-k-v][border]
}
} /// count bordered strings
hr[j]=(1ull<<(j-i))-hr[j]; /// to borderless
}
if(k>hr[n-1]){
k-=hr[n-1];
ans|=1ull<<i;
}
}
return ans;
}
}
int main(){
int n; ull b;
while(~scanf("%d%llu",&n,&b)){
using namespace bdc;
if(!n && !b) return 0;
print(calc(n,b),n);
putchar('\n');
}
return 0;
}