【2018icpc Regional Jakarta C】Smart Thief 题解

题目大意

  给出 $M$ 个个位数。现在你要用它们构造一个最短的数字串,使得这个串所有长度为 $N$ 的连续子串,至少有 $K$ 种。
  保证存在长度在 1e5 以内的答案。
  $N\leq10^5,\ M\leq10,\ K\leq \min(M^N,10^5)$

“这是我初二时的 GDOI 题。”
——1队dalao

题解

  要想到,一个子串后面添加一个数字成为下一个子串,这个类似于点通过边来转移,因此用欧拉路径来建图。

  考虑当 $N$ 很小的时候。
  把所有长度为 $N-1$ 的串视为点,表示子串的最后 $N-1$ 位。共有 $M^{N-1}$ 个点。那么点与点之间就可以连转移边了,连边表示状态转移,比如 $123$ 连一条权值为 $4$ 的边到 $234$ 去。
  对这个图跑一次欧拉路径,那么每个点加上它连出去的边,就是题目要求的一个子串,而且都是不同的,因此总的串就是最短的。

  $N$ 很大的时候呢,
  找到最小的 $N’$,使得 $M^{N’}\geq K$。那么对于所有长度为 $N$ 的子串,只看最后 $N’$ 位也足够满足 $K$ 的要求了,换句话说前 $N-N’$ 位是无关紧要的。因此把 $N$ 换成 $N’$ 按上面的做法做就行了。

代码

// 这个代码在 opentrain 上能过,在 cf 上会神奇地 WA 样例,似乎是搞爆了它的 spj ??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long LL;

const int maxtot=1e6+5, maxnp=30, maxn=1e5+5;
const LL mo=1e9+7, px=998244353;

int n,m,k,np,a[15];
LL mm,powpx[maxnp];

unordered_map<LL,int> M;
int tot;
vector<pair<int,int>> e[maxtot];
void dfs1(int k,LL now)
{
if (k==np)
{
M[now]=++tot;
return;
}
fo(i,1,m) dfs1(k+1,(now*px+a[i])%mo);
}
void dfs2(int k,LL now,int fir)
{
if (k==np)
{
int my=M[now];
fo(i,1,m)
{
int go=M[((now*px+a[i]-fir*powpx[np-1])%mo+mo)%mo];
e[my].push_back(make_pair(go,a[i]));
}
return;
}
fo(i,1,m) dfs2(k+1,(now*px+a[i])%mo,(fir==-1)?a[i]:fir);
}

int nowh[maxn],d0,st,d[maxn];
void Euler(int k,int lim)
{
int sz=e[k].size();
for(int i=nowh[k]; i<sz; i=nowh[k])
{
nowh[k]=i+1;
Euler(e[k][i].first,lim);
if (d0==lim) return;
d[++d0]=e[k][i].second;
st=k;
if (d0==lim) return;
}
}

int rc[maxn];
bool pd;
void dfs3(int k,LL now)
{
if (k==np)
{
if (M[now]==st)
{
fo(i,1,np-1) printf("%d",rc[i]);
pd=1;
}
return;
}
fo(i,1,m)
{
rc[k]=a[i];
dfs3(k+1,(now*px+a[i])%mo);
if (pd) return;
}
}

int main()
{
scanf("%d %d %d",&n,&m,&k);
fo(i,1,m) scanf("%d",&a[i]);

for(np=1, mm=m; mm<k; np++, mm*=m);

powpx[0]=1;
fo(i,1,np) powpx[i]=powpx[i-1]*px%mo;
dfs1(1,0);
dfs2(1,0,-1);

Euler(1,k);

fo(i,1,n-np) printf("%d",a[1]);
dfs3(1,0);
fd(i,d0,1) printf("%d",d[i]);
}