题意
分析
这道破题怎么写了我这么久啊啊!!菜死了TAT
很明显要数位
d
p
dp
dp。
设
n
u
m
p
o
s
,
l
i
m
i
t
,
z
e
r
o
num_{pos,limit,zero}
numpos,limit,zero 表示从高到低考虑到第
p
o
s
pos
pos 位,有没有顶着上界,是否有前导零的数的个数,
s
1
p
o
s
,
l
i
m
i
t
,
z
e
r
o
s1_{pos,limit,zero}
s1pos,limit,zero 表示从高到低考虑到第
p
o
s
pos
pos 位,有没有顶着上界,是否有前导零的前缀串之和,比如
12345
12345
12345 的前缀串是
1
,
12
,
123
,
1234
,
12345
1,12,123,1234,12345
1,12,123,1234,12345。那么转移的话枚举当前最高位的数
i
i
i,考虑
i
i
i 对单独一个
p
o
s
pos
pos 位数的贡献,令
T
i
=
∑
j
=
0
i
B
j
T_{i}=\sum\limits_{j=0}^{i}B^j
Ti=j=0∑iBj,那贡献是
i
∗
T
p
o
s
i*T_{pos}
i∗Tpos。总共有
n
u
m
num
num 个数,因此
s
1
p
o
s
,
l
i
m
i
t
,
z
e
r
o
=
∑
i
=
0
u
p
s
1
p
o
s
−
1
,
l
i
m
i
t
&
&
i
=
=
u
p
,
z
e
r
o
&
&
i
=
=
0
+
i
∗
T
p
o
s
∗
n
u
m
s1_{pos,limit,zero}=\sum\limits_{i=0}^{up}s1_{pos-1,limit\&\&i==up,zero\&\&i==0}+i*T_{pos}*num
s1pos,limit,zero=i=0∑ups1pos−1,limit&&i==up,zero&&i==0+i∗Tpos∗num。设
s
2
p
o
s
,
l
i
m
i
t
,
z
e
r
o
s2_{pos,limit,zero}
s2pos,limit,zero 表示从高到低考虑到第
p
o
s
pos
pos 位,有没有顶着上界,是否有前导零的所有子串之和。那么转移是类似的,就是
p
o
s
−
1
pos-1
pos−1 位的子串和加上最高位参与的前缀串之和即可。需要注意的是,如果有前导
0
0
0,那最高位选
0
0
0 前缀串之和是不能算进
s
2
s2
s2 的。
这样子的复杂度是
O
(
N
B
)
O(NB)
O(NB) 的。
然后发现转移的时候,只用分三种情况,
i
=
0
i=0
i=0,
i
=
u
p
i=up
i=up,
i
∈
[
1
,
u
p
−
1
]
i\in[1,up-1]
i∈[1,up−1]。第三种的每个
i
i
i 是等价的,可以通过等差数列求和来快速得到。转移复杂度这样子就降到了
O
(
1
)
O(1)
O(1)。
总之是一道不是很难的题(为什么我感觉这么难啊
代码如下(注释掉的部分是暴力转移的)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
void debug_out(){
cerr << endl;
}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){
cerr << " " << to_string(H);
debug_out(T...);
}
#ifdef local
#define debug(...) cerr<<"["<<#__VA_ARGS__<<"]:",debug_out(__VA_ARGS__)
#else
#define debug(...) 55
#endif
const int N = 1e5 + 5, maxn = 1e5, mod = 20130427;
int T[N], a[N], B, ans;
struct DP{
int n, s1, s2;
}dp[N][2][2];
int vis[N][2][2];
DP dfs(int pos, int f1, int f2){
if(pos == -1) return {1, 0, 0};
if(vis[pos][f1][f2]) return dp[pos][f1][f2];
vis[pos][f1][f2] = 1;
int up = f1? a[pos]: B - 1;
DP res = {0, 0, 0};
/*for(int i = 0; i <= up; i++){
DP t = dfs(pos - 1, f1 && i == up, f2 && i == 0);
res.n = (res.n + t.n) % mod;
res.s1 = (res.s1 + (LL)t.n * i % mod * T[pos] % mod + t.s1) % mod;
res.s2 = (res.s2 + t.s2 + (LL)t.n * i % mod * T[pos] % mod + t.s1 * (!(f2 && i == 0))) % mod;
}*/
int i = 0;
DP t = dfs(pos - 1, f1 && i == up, f2 && i == 0);
res.n = (res.n + t.n) % mod;
res.s1 = (res.s1 + (LL)t.n * i % mod * T[pos] % mod + t.s1) % mod;
res.s2 = (res.s2 + t.s2 + (LL)t.n * i % mod * T[pos] % mod + t.s1 * (!(f2 && i == 0))) % mod;
if(up > 0){
i = up;
t = dfs(pos - 1, f1 && i == up, f2 && i == 0);
res.n = (res.n + t.n) % mod;
res.s1 = (res.s1 + (LL)t.n * i % mod * T[pos] % mod + t.s1) % mod;
res.s2 = (res.s2 + t.s2 + (LL)t.n * i % mod * T[pos] % mod + t.s1 * (!(f2 && i == 0))) % mod;
if(up > 1){
int s = ((LL)up * (up - 1) / 2) % mod;
t = dfs(pos - 1, 0, 0);
res.n = (res.n + (LL)t.n * (up - 1) % mod) % mod;
res.s1 = (res.s1 + (LL)t.n * s % mod * T[pos] % mod + (LL)t.s1 * (up - 1) % mod) % mod;
res.s2 = (res.s2 + (LL)t.s2 * (up - 1) + (LL)t.n * s % mod * T[pos] % mod + (LL)t.s1 * (up - 1) % mod) % mod;
}
}
return dp[pos][f1][f2] = res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> B;
T[0] = 1;
for(int i = 1; i <= maxn; i++) T[i] = ((LL)T[i - 1] * B % mod + 1) % mod;
int n;
cin >> n;
n--;
for(int i = n; i >= 0; i--) cin >> a[i];
if(a[n]){
for(int i = 0; i <= n; i++){
if(a[i]){
a[i]--;
break;
}
a[i] = B - 1;
}
if(!a[n]) n--;
ans -= dfs(n, 1, 1).s2;
}
cin >> n;
n--;
for(int i = n; i >= 0; i--) cin >> a[i];
memset(vis, 0, sizeof(vis));
// debug(ans);
ans += dfs(n, 1, 1).s2;
cout << (ans % mod + mod) % mod << '\n';
return 0;
}