zoukankan      html  css  js  c++  java
  • [BZOJ]1026[SCOI2009]windy数

    题目链接:[SCOI2009]windy数

     题意:

    求[l,r]之间的有多少个数满足:不包含前导0,且相邻两位数字差大于等于2。

    题解:  

    第一次不看题解一遍通过数位dp祭(虽然以前做过这道题,但是已经忘了)。

    数位dp一直是恶心我的难点,这道题刚好是一道很简单的的数位dp,于是想尝试一下。

    数位dp肯定要记忆化搜索,其他的奇怪实现方法我觉得都没有记搜简单明了且方便实现。

    dfs(i, f, lst, limit)

    表示第i位,是否有前导0,前面一个数是多少,是否碰到上限的方案数。

    于是枚举当前位置的数,需要考虑以下几种情况。

    首先当现在枚举的数是0的时候,会出现传递前面前导0的作用,于是判断前导0。

    然后如果当前顶到上界,需要考虑当前数字是否小于上界。

    如果没顶到上界,则需要考虑当前数字跟上一位差值是多少。

    记住每种情况都要分类是否前面为前导0,因为前导0跟第一个数字不用比较差值大于等于2。

    #include <bits/stdc++.h>
    #define Mid ((l + r) / 2)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    int dp[20][2][20][2];
    int a[1009], cnt;
    int dfs(int res, int f, int lst, int limit) {
        if(dp[res][f][lst][limit] != -1) return dp[res][f][lst][limit];
        dp[res][f][lst][limit] = 0;
        if(res == 0) return dp[res][f][lst][limit] = 1;
        for(int i = 0; i < 10; i++) {
            if(i == 0) {
                if(f == 1) dp[res][f][lst][limit] += dfs(res - 1, 1, 0, 0);
                else if(lst >= 2) dp[res][f][lst][limit] += dfs(res - 1, 0, 0, limit && (i == a[res]));
            } else if(limit && i <= a[res]) {
                if(f == 1) dp[res][f][lst][limit] += dfs(res - 1, 0, i, limit && (i == a[res]));
                else if(abs(i - lst) >= 2) dp[res][f][lst][limit] += dfs(res - 1, 0, i, limit && (i == a[res]));
            } else if(!limit) {
                if(f == 1 || abs(i - lst) >= 2)
                    dp[res][f][lst][limit] += dfs(res - 1, 0, i, 0);
            }
        }
        return dp[res][f][lst][limit];
    }
    signed main()
    {
    
        int l = read() - 1, r = read();
        int cntl, cntr;
        cnt = 0;
        while(r > 0) a[++cnt] = r % 10, r /= 10;
        memset(dp, -1, sizeof(dp));
        cntr = dfs(cnt, 1, 0, 1);
        cnt = 0;
        while(l > 0) a[++cnt] = l % 10, l /= 10;
        memset(dp, -1, sizeof(dp));
        cntl = dfs(cnt, 1, 0, 1);
        printf("%d
    ", cntr - cntl);
        return 0;
    }
    View Code
  • 相关阅读:
    orcale 之数据操作
    快速排序-java
    javadoc错误: 编码gbk的不可映射字符
    javaweb-url /
    javaWeb-mvc之利用c3p0写入数据库出现乱码
    java基础-jdbc——三种方式加载驱动建立连接
    老调重弹:JDBC系列之<驱动加载原理全面解析) ----转
    java基础-反射之Class.forName
    mvc-servlet---servletContext与servletConfig2
    mvc-servlet---ServletConfig与ServletContext对象详解(转载)
  • 原文地址:https://www.cnblogs.com/onglublog/p/14728498.html
Copyright © 2011-2022 走看看