zoukankan      html  css  js  c++  java
  • [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;
    }
    
    
  • 相关阅读:
    Linux makefile教程之概述一[转]
    Valid Parentheses
    Letter Combinations of a Phone Number
    机器学习经典分类算法 —— C4.5算法(附python实现代码)
    3Sum Closest
    3Sum
    Integer to Roman
    寒假文献阅读(四)
    Longest Common Prefix
    Roman to Integer
  • 原文地址:https://www.cnblogs.com/LiM-817/p/10887225.html
Copyright © 2011-2022 走看看