设(f[n])为串(s[1...n])的答案,(sdif[n])为串(s[1...n])有多少个不同的串
假设串(n)的长度为(len[n]),现在在串(s[1...n])后面增加一个字符p
考虑增加字符(p)后相较于原来的字符串多了哪些子串,
明显是(s[1...n]+p,s[2...n]+p,s[3...n]+p,...,p)
对原来答案增加的贡献是(newp = sdif[n]*B+(len[n]+1)*p),所以现在的答案是$ newp+lastans$;
定义(S[n])为(0+1+2+3+...+n)的和
假设现在随便填(先考虑位数不足的情况)
每个位置有(0~B-1)共(B)种填法
同时因为我们注意到了一共会有(B)种填法,对原来的(f[n])的答案转移时也应该$*B $
所以对原来增加的贡献为(sum newp = B^2*sdif[n]+(len[n]+1)*S[B-1]);
但是这是前面只有一种串的情况
假设以(n)为结尾的有(sdif[n])种不同的串,
那么实际贡献为(sum newp = B^2*suf[n]+sdif[n]*(len[n]+1)*S[B-1])
现在考虑在串(s[1...n])加入一个字符(p)后,包含(p)的后缀的计算。
对于不同的串的个数(sdif[n]),转移明显是(sdif[n]*B)
接着把需要维护的东西放在数位dp上做。
考虑维护以(i)为结尾的后缀和(prex_{i,0/1}),以(i)为结尾的串的答案(f_{i,0/1}),以(i)为结尾的不同的串的个数(sdif_{i,0/1})
(0,1)分别是不卡/卡上界
对于第一次dp,计算(len<n(m))的答案,明显是随便填;
对于第二次dp,计算位数相等时的答案,对于卡不卡上界分类讨论
(f_{i,0})有两种转移,一种是从上一次不卡上界的转移,那么这一位随便填,有(B)种填法
另外一种是从上一次卡上界的转移,这一位只能填([0,a_i-1])一共(a_i)种填法,然后用后缀和更新
(f_{i,1})同理,只能从(f_{i-1,1})转移,然后用后缀和更新。
#include<cstdio>
#include<cstring>
const int N = 3e5+7;
typedef long long LL;
const long long p = 20130427;
#define R register
int B;
LL S0[N], prex[N][2], sdif[N][2], f[N][2];
inline int max(LL a, LL b) {
return a > b ? a : b;
}
inline LL dp(LL *a, int len) {
if (!len || (len == 1 && !a[1])) return 0;
memset(prex, 0, sizeof(prex));
memset(sdif, 0, sizeof (sdif));
memset(f, 0, sizeof(f));
LL ans = 0;
if (len > 1) {
sdif[1][0] = B - 1LL, prex[1][0] = S0[B - 1], f[1][0] = S0[B - 1];
ans = (ans + f[1][0]) % p;
for (R int i = 2; i < len; i++) {
sdif[i][0] = (sdif[i - 1][0] * B % p) % p;
prex[i][0] = (prex[i - 1][0] * B % p * B % p + S0[B - 1] * i % p * sdif[i - 1][0] % p) % p;
f[i][0] = (f[i - 1][0] * B % p + prex[i][0]) % p;
ans = (ans + f[i][0]) % p;
}
}
memset(prex, 0, sizeof(prex));
memset(sdif, 0, sizeof(sdif));
memset(f, 0LL, sizeof(f));
sdif[1][0] = max(a[1] - 1, 0);
prex[1][0] = S0[max(a[1] - 1, 0)];
f[1][0] = prex[1][0];
sdif[1][1] = 1, prex[1][1] = a[1];
f[1][1] = prex[1][1];
for (R int i = 2; i <= len; i++) {
sdif[i][0] = (sdif[i - 1][0] * B % p + sdif[i - 1][1] * a[i] % p) % p;
sdif[i][1] = sdif[i - 1][1];
prex[i][0] = (prex[i - 1][0] * B % p * B % p + sdif[i - 1][0] * S0[B - 1] % p * i % p
+ prex[i - 1][1] * B % p * a[i] % p + sdif[i - 1][1] * S0[max(a[i] - 1, 0)] % p * i % p) % p;
prex[i][1] = (prex[i - 1][1] * B % p + i % p * a[i] % p);
f[i][0] = ((f[i - 1][0] * B % p) + (f[i - 1][1] * a[i] % p) + prex[i][0]) % p;
f[i][1] = (f[i - 1][1] + prex[i][1]) % p;
}
ans = (ans + f[len][0] + f[len][1]) % p;
return ans;
}
LL A[N], Bx[N], tmp[N];
int main() {
LL x, y;
scanf("%d", &B);
for (R int i = 1; i <= B; i++) S0[i] = (S0[i - 1] + i) % p;
int n, m;
scanf("%d", &n);
for (R int i = 1; i <= n; i++) scanf("%lld", &A[i]);
for (R int i = n; i >= 1; i--) {
if (A[i] > 0) {
A[i]--;
if (i == 1 && n != 1 && !A[i]) {
for (R int j = 2; j <= n; j++)
tmp[j - 1] = A[j];
for (R int j = 1; j < n; j++)
A[j] = tmp[j];
n--;
}
break;
}
A[i] = B - 1LL;
}
scanf("%d", &m);
for (R int i = 1; i <= m; i++) scanf("%lld", &Bx[i]);
//printf("%lld %lld
", dp(Bx, m), dp(A, n));
printf("%lld", ((dp(Bx, m) - dp(A, n)) % p + p) % p);
}