zoukankan      html  css  js  c++  java
  • HDU 3652:B-number(数位DP)

    亮点:

    收获:降一些时间复杂度可能带来编程复杂度。如果编程复杂度太高,而且时间允许的话,试着用一些冗余的状态来降低编程复杂度。

    查询和正常DP的差别就在于:查询的时候有限制(最大不能超过那个数),而正常的时候没有

    类型:数位DP

    题意:找1~n内有多少能被13整除且含“13”这个子串的数。

    方法:

    (我的,想的比较乱的方法)

    dp[i][d][mod]  表示d开头的i位数中含有“13”这个子串且%13==mod的数的个数

    则:

    那么下一个余数nextMod = ((mod-j*10i-1)%13+13)%13

    dp[i][d][mod]  =  

                              1) d != 1:  ∑dp[i-1][j=(0~9)][nextMod]

                              2) d == 1:  ∑dp[i-1][j=(0~2,4~9)][nextMod] + ((10i-2 - nextnextMod-1/*-1去掉0*/)/13+1/*+1补上被去掉的那个*/)(接下来10i-1个数里,%13 == nextnextMod 的数。nextnextMod = ((next-3*10i-1)%13+13)%13)

    但是,查询的时候,如果是1301,按照上面差的话,实际上只有1300和1301两个数,但是我们会算1300~1399这些数。 所以这里也不一样!。

    唉,这种方法,d==1的情况太复杂,陷阱很多。+1-1的陷阱,然后查询的时候有陷阱。总之是一个很小心才能做出来的方法。

    坑:

    查询和正常DP的差别就在于:查询的时候有限制(最大不能超过那个数),而正常的时候没有。所以每一步都要小心,把查询和正常DP分开处理。这样才能对。另外,如果能更清晰一点,就不要这么写。。太容易错了。

    方法二:(网上)

    ¨for x = 0 ~ 9
    ¨  if k = 1 //要求要包含13
    ¨    f[i,j,k,l] = f[i - 1,x,1,(l - j*10^(i-1))%13];
    ¨    if j = 1 and x = 3 //已经有13了。
    ¨      f[i,j,k,l] = f[i,j,k,l] +
    ¨                   f[i - 1,x,0,(l - j*10^(i-1))%13];
    ¨  else //不要求包含13
    ¨    if not (j = 1 and x = 3)
    ¨      f[i,j,k,l] = f[i - 1,x,0,(l - j*10^(i-1))%13];

    这个方法多设了一维(包含和不包含),但清晰很多~

    这就是我降维降出的编程复杂度…………T  T

    收获:降一些时间复杂度可能带来编程复杂度。如果编程复杂度太高,而且时间允许的话,试着用一些冗余的状态来降低编程复杂度。

    #include <cstdio>
    #include <cstring>
    
    int dp[20][10][13];
    int num[20];
    int n;
    
    int dfs(int i, int d, int mod, bool isQuery) {
        if (!isQuery && dp[i][d][mod] != -1) {
            return dp[i][d][mod];
        }
        if (i == 1) {
            return dp[i][d][mod] = 0;
        }
        int end = isQuery?num[i-1]:9;
        int ans = 0;
        int ten = 1;
        for (int j = 0; j < i-1; j++) ten *= 10;
        int nextMod = ((mod-d*ten)%13 + 13)%13;
        for (int j = 0; j <= end; j++) {
            if (d == 1 && j == 3) {
                int nnxtMod = ((nextMod-(ten/10)*j)%13+13)%13;
                int thenum = (isQuery && j==end) ?(n%(ten/10)+1):(ten/10);
                int lala = thenum - nnxtMod - 1;
                if (lala >= 0) ans += lala/13+1;
                continue;
            }
            ans += dfs(i-1,j,nextMod,isQuery && j==end);
        }
        if (!isQuery) dp[i][d][mod] = ans;
        return ans;
    }
    
    int cal(int x) {
        int len = 0;
        while (x){
            num[++len] = x%10;
            x/=10;
        }
        return dfs(len+1, 0, 0, true);
    }
    
    int main() {
        memset(dp,-1,sizeof(dp));
        while (~scanf("%d", &n)) {
            printf("%d
    ", cal(n));
        }
        return 0;
    }
  • 相关阅读:
    在二进制与文本之间转换plist文件
    iOS 音频分贝的计算
    iOS 圆形水波浪效果实现
    iOS画圆、画线
    iOS IM开发准备工作(四)CocoaAsyncSocket的使用
    iOS IM开发准备工作(三)乱说Socket
    iOS IM开发准备工作(二)protobuf-objc安装及使用
    iOS IM开发准备工作(一)XML解析
    iOS IM开发blog写作计划
    西游记倒着看。。我从贴吧看来的
  • 原文地址:https://www.cnblogs.com/shinecheng/p/3594994.html
Copyright © 2011-2022 走看看