[CF628D]Magic Numbers 题解

比较友好的数位(dp)练手题。

(dp(i,j,k=0/1))表示还剩(i)位,前几位表示的数(equiv ext{ j (mod m)}),此位是否为偶数位的数的个数。

如果(k=0),那么这一位一定不能是(d)。否则一定得是(d)。大力转移即可。
边界:(dp(0,0,0/1)=1).

特别注意本题并不需要高精(+1)操作,只需要特判(b)一个数即可。

/**
 * @Author: Mingyu Li
 * @Date:   2019-03-10T15:39:26+08:00
 * @Email:  class11limingyu@126.com
 * @Filename: cf628D.cpp
 * @Last modified by:   Mingyu Li
 * @Last modified time: 2019-03-10T20:44:04+08:00
 */

#include <bits/stdc++.h>
#define tpname typename
#define Go(i , x , y) for(register int i = x; i <= y; i++)
#define God(i , y , x) for(register int i = y; i >= x; i--)
typedef long long LL;
typedef long double ld;
typedef unsigned long long ULL;
template < tpname T > void sc(T& t) {
  char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
  while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < tpname T , tpname... Args > void sc(T& t , Args&... args) {sc(t); sc(args...);}
template < tpname T > T mul(T x , T y , T _) {
  x %= _,y %= _; return ((x * y - (T)(((ld)x * y + 0.5) / _) * _) % _ + _) % _;
}

const int N = 2000 + 5;
const int mod = (int)(1e9 + 7);
int m , D , p;
std::string a,b;
int d[2000];
// f[i][j][k]:
// 还剩i位 前几位组成的数%m = j  是否是偶数位

int dp[N][N][2];
int f(int i , int j ,int k) {
  if(dp[i][j][k] != -1) return dp[i][j][k];
  if(i == 0) return dp[i][j][k] = j%m == 0 ? 1 : 0;

  int ans = 0;
  Go(x , 0 , 9) {
    if(k == 1 && x != D) continue;
    if(k == 0 && x == D) continue;
    ans = (ans + f(i-1 , (j*10 + x)%m , k^1)) % mod;
  }
  return dp[i][j][k] = ans;
}

int cal(std::string x) {
  p = 0;
  while(!x.empty()) {
    d[p++] = x.back() - '0';
    x.pop_back();
  }

  int op=0 , ans=0;
  God(i , p-1 , 1) {
    Go(j , 1 , 9) {
      if(j == D) continue;
      ans = (ans + f(i-1 , j%m , 1)) % mod;
    }
  }

  op = 0; int lst = 0;
  God(i , p-1 , 0) {
    Go(j , (i == p-1) ? 1 : 0 , d[i] - 1) {
      if(op == 1 && j != D) continue;
      if(op == 0 && j == D) continue;
      ans = (ans + f(i , (lst * 10 + j) % m , op^1)) % mod;
    }
    if(op == 1 && d[i] != D) break;
    if(op == 0 && d[i] == D) break;
    op = 1 - op;
    lst = (lst * 10 + d[i]) % m;
  }

  return ans;
}
int main() {
  memset(dp , -1 , sizeof(dp));
  sc(m , D);
  std::cin >> a >> b;
  int ans = (cal(b) - cal(a) + mod) % mod;
  bool f = 1 , op = 0;

  int m1 = 0;
  Go(i , 0 , (int)(b.size()) - 1) {
    if(op == 0 && b[i]-'0'== D) f = 0;
    if(op == 1 && b[i]-'0' != D) f = 0;
    op = op^1;
  }
  for(char x : b) m1 = (m1 * 10 + x - '0')%m;
  ans += (f & (m1 == 0));
  ans %= mod;
  std::cout << ans << std::endl;
  return 0;
}

原文地址:https://www.cnblogs.com/LiM-817/p/10887225.html