版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意
Fish数数玩的规则是:
-
确定数数的进制B
-
确定一个数数的区间[L, R]
对于[L, R] 间的每一个数,把该数视为一个字符串,列出该字符串的每一个(连续的)子串对应的B进制数的值。
对所有列出的数求和。
思路
数数好题。又是一道我不会的数数题。。。
我的思路:考虑每一位的贡献,就是所有前缀的长度和×后缀的长度和×当前位置的数的权值。实在太烦了根本写不出来。
题解思路:考虑在一个已有的串后面加上一个数,增加的是所有的后缀的权值。记录到当前位置时的权值和,后缀权值和,数的个数和数的位数之和就可以方便的递推了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 20130427;
int B, n, m, a[N], b[N];
int f[N][2], g[N][2], h[N][2], c[N][2];
template<class T>inline void read(T &x){
x = 0; bool fl = 0; char c = getchar();
while (!isdigit(c)){if (c == '-') fl = 1; c = getchar();}
while (isdigit(c)){x = (x<<3)+(x<<1)+c-'0'; c = getchar();}
if (fl) x = -x;
}
void _minus()
{
a[n]--;
int i = n;
while (a[i] < 0 && i >= 1){
a[i] += B;
a[i-1]--;
i--;
}
if (i == 0){
a[1] = 0;
n = 1;
}
else{
i = 1;
while (a[i] == 0 && i <= n) i++;
if (i > n) n = 1;
else{
for (int j = i; j <= n; ++ j)
a[j-i+1] = a[j];
n -= i-1;
}
}
i = 1;
while (b[i] == 0) i++;
for (int j = i; j <= m; ++ j)
b[j-i+1] = b[j];
m -= i-1;
}
int calc(int x){
return 1LL*x*(x+1)/2%mod;
}
int solve(int n, int *a)
{
c[1][1] = 1; c[1][0] = a[1]-1; // c -> 数的个数
h[1][1] = 1; h[1][0] = a[1]-1; // h -> 位数之和
g[1][1] = a[1]; g[1][0] = calc(a[1]-1); // g -> 后缀权值和
f[1][1] = a[1]; f[1][0] = calc(a[1]-1); // f -> 权值和
for (int i = 2; i <= n; ++ i){
c[i][0] = (1LL*c[i-1][0]*B%mod + 1LL*c[i-1][1]*a[i]%mod + B-1) % mod;
c[i][1] = 1;
h[i][0] = (1LL*h[i-1][0]*B%mod + 1LL*h[i-1][1]*a[i]%mod + c[i][0]) % mod;
h[i][1] = h[i-1][1]+1;
g[i][0] = (1LL*g[i-1][0]*B%mod*B%mod + 1LL*(h[i-1][0]+c[i-1][0]+1)*calc(B-1)%mod) % mod;
if (a[i] >= 1) (g[i][0] += 1LL*g[i-1][1]*B%mod*a[i]%mod + 1LL*(h[i-1][1]+c[i-1][1])*calc(a[i]-1)%mod) %= mod;
g[i][1] = (1LL*g[i-1][1]*B%mod + 1LL*(h[i-1][1]+c[i-1][1])*a[i]%mod) % mod;
f[i][0] = (1LL*f[i-1][0]*B%mod + g[i][0]) % mod;
if (a[i] >= 1) (f[i][0] += 1LL*f[i-1][1]*a[i]%mod) %= mod;
f[i][1] = (f[i-1][1] + g[i][1]) % mod;
}
return (f[n][0] + f[n][1]) % mod;
}
int main()
{
read(B);
read(n);
for (int i = 1; i <= n; ++ i)
read(a[i]);
read(m);
for (int i = 1; i <= m; ++ i)
read(b[i]);
_minus();
printf("%d\n", (solve(m, b)-solve(n, a)+mod)%mod);
return 0;
}