题解 昵称
- 一些方案数会爆 long long 但我们只需知道它是否 > 某个数的情况下我们可以让这个方案数时刻对 1e18 取 min
\(s\) 弄那么大似乎没什么用,不影响数位 DP
令 \(f_{i, j}\) 为考虑到第 \(i\) 位,与 \(s\) 匹配长度为 \(j\) 的方案数
这里转移需要 kmp 自动机优化
最后按位确定即可
话说 0 有前导 0 吗?
复杂度大约 \(O((|s|)^2\log n)\) 吧
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2050
#define ll long long
#define int long long
#define int128 __int128
#define ull unsigned long long
int n, m;
char s[N];
namespace force{
char sta[N], top;
ull h[N], pw[N], tem;
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
bool check(int t) {
top=0;
do {sta[++top]=t%10; t/=10;} while (t);
reverse(sta+1, sta+top+1);
for (int i=1; i<=top; ++i) h[i]=h[i-1]*base+sta[i];
for (int i=m; i<=top; ++i) if (hashing(i-m+1, i)==tem) return 1;
return 0;
}
void solve() {
pw[0]=1;
for (int i=1; i<N; ++i) pw[i]=pw[i-1]*base;
for (int i=1; i<=m; ++i) tem=tem*base+s[i];
for (int i=0; ; ++i) {
if (check(i)) --n;
if (!n) {cout<<i<<endl; break;}
}
}
}
namespace task1{
ll ans[N];
int nxt[N], tran[N][12];
int128 dp[N][N], pw[N];
int128 dfs(int u, int k) {
if (k==m) return pw[u];
if (!u) return 0;
if (~dp[u][k]) return dp[u][k];
int128* t=&dp[u][k]; *t=0;
for (int i=0; i<10; ++i) {
// int len=k;
// while (len && i!=s[len+1]) len=nxt[len];
// if (i==s[len+1]) ++len;
int len=tran[k][i];
*t+=dfs(u-1, len);
}
return *t;
}
void solve() {
memset(dp, -1, sizeof(dp));
pw[0]=1;
for (int i=1; i<=50; ++i) pw[i]=pw[i-1]*10;
nxt[1]=0;
for (int i=2,j=0; i<=m; ++i) {
while (j && s[j+1]!=s[i]) j=nxt[j];
if (s[j+1]==s[i]) ++j;
nxt[i]=j;
}
for (int i=0; i<=m; ++i)
for (int j=0; j<10; ++j)
if (s[i+1]==j) tran[i][j]=i+1;
else tran[i][j]=tran[nxt[i]][j];
int k=0;
for (int i=m+25; i; --i) {
// cout<<"i: "<<i<<endl;
if (k==m) {
int top=0;
--n;
while (n) {ans[++top]=n%10; n/=10;}
break;
}
for (int j=0; j<10; ++j) {
// int len=k;
// while (len && j!=s[len+1]) len=nxt[len];
// if (j==s[len+1]) ++len;
int len=tran[k][j];
int128 t=dfs(i-1, len);
// cout<<"j: "<<j<<' '<<n<<' '<<(ll)t<<endl;
// cout<<"dfs: "<<i-1<<' '<<(len)<<endl;
if (n>t) n-=t;
else {
ans[i]=j;
k=len;
break;
}
}
}
int pos=m+25;
while (pos>1 && !ans[pos]) --pos;
for (int i=pos; i; --i) printf("%lld", ans[i]); printf("\n");
}
}
signed main()
{
freopen("nickname.in", "r", stdin);
freopen("nickname.out", "w", stdout);
scanf("%s%lld", s+1, &n);
m=strlen(s+1);
for (int i=1; i<=m; ++i) s[i]-='0';
// force::solve();
task1::solve();
return 0;
}