• 数位dp进阶(hdu2089,3652)


    之前的文章已经讲过如何求1—r中的特殊数,这篇博客就来讲些进阶操作;

    直接看例题(hdu2089):

    (题目是中文的我就不写大意了)

    这题与hdu3555最大的区别就是规定了l,不再以1开始;

    解决这个问题也很简单,利用前缀和的思想,先计算1—l-1特殊数的数量,在计算l—r的数量,相减就是答案了;

    附上丑陋的代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define int long long
     5 const int MAXN=20;
     6 int n,r,t,digit[MAXN],dp[MAXN][MAXN],t2,l;
     7 int dfs(int pos,int pre,bool limit)
     8 {
     9     if(pos==0) return 1;
    10     if(!limit && dp[pos][pre] != 0)
    11     {
    12         return dp[pos][pre];
    13       }
    14     int up=9;
    15     if(limit) up=digit[pos]; 
    16     int ans=0;
    17     for(int i=0;i<=up;++i)
    18     if(pre==6&&i==2||i==4)
    19         continue;
    20     else
    21     {
    22         ans+=dfs(pos-1,i,limit&&(i==digit[pos]));
    23     }
    24     if(!limit)
    25     {
    26         dp[pos][pre] = ans;
    27     }
    28     return ans;
    29 }
    30 void solve(int y,int x)
    31 {
    32     t=0;
    33     int xx=x;
    34     while(x>0)
    35     {
    36         ++t;
    37         digit[t]=x%10;
    38         x=x/10;
    39     }
    40     int ans2=dfs(t,0,1);
    41     t=0;
    42     --y;
    43     xx=y;
    44     while(y>0)
    45     {
    46         ++t;
    47         digit[t]=y%10;
    48         y=y/10;
    49     }
    50     int ans=dfs(t,0,1);
    51     printf("%lld
    ",ans2-ans);
    52 }
    53 main()
    54 {
    55     while(cin>>l>>r)
    56     {
    57         if(l==0&&r==0) return 0;
    58         solve(l,r);
    59     }
    60 }

    例题2(hdu3652):

    手(帮)动(你)翻译(太懒了,不想写题意)

    这题又与上题有些不同,不仅要满足含13,还要整除13;

    具体实现也不难,只要在搜索的同时记录数字除以13的余数;

    怎么传递呢?这又要考小学奥数了,余数的性质;

    4)a与b的和除以c的余数(a、b两数除以c在没有余数的情况下除外),等于a,b分别除以c的余数之和(或这个和除以c的余数)。例如,23,16除以5的余数分别是3和1,所以(23+16)除以5的余数等于3+1=4。注意:当余数之和大于除数时,所求余数等于余数之和再除以c的余数。例如,23,19除以5的余数分别是3和4,所以(23+19)除以5的余数等于(3+4)除以5的余数。
    
    (5)a与b的乘积除以c的余数,等于a,b分别除以c的余数之积(或这个积除以c的余数)。例如,23,16除以5的余数分别是3和1,所以(23×16)除以5的余数等于3×1=3。注意:当余数之积大于除数时,所求余数等于余数之积再除以c的余数。例如,23,19除以5的余数分别是3和4,所以(23×19)除以5的余数等于(3×4)除以5的余数。
    
    性质(4)(5)都可以推广到多个自然数的情形。

    太长不想看也不要紧,总结一下就是$a imes 100+b imes 10+c$ % $ d = a imes 100 $%$ d+b imes 10 $%$ d +c $%$ d$;

    这有什么用呢,这个性质可以让我们在传递的时候,只要把余数$ imes 10$再加上现在选取的数 mod 13就可以了,最后看是否满足条件

    附上水代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define int long long
     5 const int MAXN=20;
     6 int n,r,t,digit[MAXN],dp[MAXN][MAXN][MAXN][2];
     7 int dfs(int pos,int pre,bool limit,int mo,bool have,int sum)
     8 {
     9     if(pos==0)
    10     {
    11         if(mo==0&&have)
    12         {
    13             return 1;
    14         }
    15         else
    16             return 0;
    17     }
    18     if(!limit&&dp[pos][pre][mo][have]!=0) return dp[pos][pre][mo][have];
    19     int up=9;
    20     if(limit) up=digit[pos];
    21     int ans=0;
    22     for(int i=0;i<=up;++i)
    23     if(pre==1&&i==3)
    24         ans+=dfs(pos-1,i,limit&&(i==digit[pos]),(mo*10+i)%13,1,sum*10+i);
    25     else
    26         ans+=dfs(pos-1,i,limit&&(i==digit[pos]),(mo*10+i)%13,have,sum*10+i);
    27     if(!limit) dp[pos][pre][mo][have]=ans;
    28     return ans;
    29 }
    30 void solve(int x)
    31 {
    32     t=0;
    33     int xx=x;
    34     while(x>0)
    35     {
    36         ++t;
    37         digit[t]=x%10;
    38         x=x/10;
    39     }
    40     printf("%lld
    ",dfs(t,0,1,0,0,0));
    41 }
    42 main()
    43 {
    44     while(cin>>r)
    45     {
    46         solve(r);
    47     }
    48 }

    又这样水过了一篇博客;

  • 相关阅读:
    6、方法
    5、封装
    4、循环
    3、判断
    2、基本语法
    1、基本框架
    CodeForces 681C Heap Operations(模拟)
    CodeForces 682C Alyona and the Tree(广搜 + 技巧)
    URAL 2099 Space Invader题解 (计算几何)
    HDU 5833 (2016大学生网络预选赛) Zhu and 772002(高斯消元求齐次方程的秩)
  • 原文地址:https://www.cnblogs.com/JinLeiBo/p/9726820.html
Copyright © 2020-2023  润新知