luogu 3281 数数

\(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\n", dp(Bx, m), dp(A, n));
  printf("%lld", ((dp(Bx, m) - dp(A, n)) % p + p) % p);
}

posted @ 2019-10-12 19:28  ComeIntoCalm  阅读(...)  评论(...编辑  收藏