zoukankan      html  css  js  c++  java
  • [BZOJ1026][SCOI2009]windy数 解题报告|数位dp

    Description

      windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?

      一直还是有点怕数位DP的...包括今天做这道简单的小题也花了很久的时间处理细节。

      首先大体的思路非常明显,定义一个DP f[i,j]表示第i位放数字j有多少种方法,可以通过前一位的一些满足的数字推出这一位。

      但是如何来解决在某个数A的范围内呢...?

      并且一旦前面的没有取满,这一位都是可以0..9任意取的

      并且还要考虑以这一位为开头的情况

      没有前导零,也就是说当这一位为0的时候是不能作为开头的。

      思考了一会儿,想出了一种方案。f[i,j]表示第i为放数字j并且从1~i并排除取到原数的方案数

      那么通过f[i-1]然后枚举0~9就可以先得出初步的f[i](因为i-1位以前都没有取到满了,这一位随便怎么取都不会超过原数

      第二部分就是当前数为起点,那么我们枚举1~9,inc(f[i][j])就可以了

      还有一种情况,就是i-1位已经取满了,当前这位只能取0~num[i]这些数(num[i]表示原数在第i位的数字)

      但是我们只能枚举到num[i]-1,因为要维护f[i]这个数组的性质:没有取到满

      注意细节:第三种情况能够转移当且仅当1~i-1位都满足windy数的性质 (这里我们可以用一个bool类型标记)

      处理完之后再判断1~i是否满足windy数的性质

      f[最后一位][0..9]就是答案。

      其实还没有结束...别忘了原数,如果那个bool类型到最后还是为真,说明原数也是一个windy数

      但是显然我们在f数组里是不会统计到原数的,这个时候还要答案+1

      最后还有一个细节,就是特判0的情况,虽然题目保证>=1但是我们要的答案是solve(r)-solve(l-1),还是会即算到0的情况

      要特判solve(0)=0

      前几天写惯了树剖今天几道小题真是爽啊...

      

     1 /**************************************************************
     2     Problem: 1026
     3     User: mjy0724
     4     Language: Pascal
     5     Result: Accepted
     6     Time:0 ms
     7     Memory:228 kb
     8 ****************************************************************/
     9  
    10 program bzoj1026;
    11 var i,l,r:longint;
    12     w,num:array[-1..15]of longint;
    13     f:array[-1..15,0..9]of longint;
    14  
    15 function solve(p:longint):longint;
    16 var i,j,k,ans:longint;
    17     flag:boolean;
    18 begin
    19         if p=0 then exit(0);
    20     fillchar(f,sizeof(f),0);
    21     for i:=9 downto 1 do if p div w[i]>0 then break;
    22         if p div w[i]>0 then inc(i);
    23     for j:=i downto 1 do num[j]:=p div w[j-1] mod 10;
    24         for j:=1 to num[i]-1 do f[i,j]:=1;
    25     flag:=true;
    26     for i:=i-1 downto 1 do
    27     begin
    28         for j:=0 to 9 do
    29             for k:=0 to 9 do if abs(j-k)>=2 then inc(f[i,j],f[i+1,k]);
    30         for j:=1 to 9 do inc(f[i,j]);
    31         if flag then for j:=0 to num[i]-1 do if abs(j-num[i+1])>=2 then inc(f[i,j]);
    32         if abs(num[i]-num[i+1])<2 then flag:=false;
    33     end;
    34     ans:=0;
    35     for i:=0 to 9 do inc(ans,f[1,i]);
    36         if flag then inc(ans);
    37     exit(ans);
    38 end;
    39  
    40  
    41 begin
    42     w[0]:=1;
    43     for i:=1 to 9 do w[i]:=w[i-1]*10;
    44         readln(l,r);
    45     writeln(solve(r)-solve(l-1));
    46 end.

       

  • 相关阅读:
    CSS边框(圆角、阴影、背景图片)
    CSS3浏览器兼容
    HTML5全局属性
    HTLM5新增属性
    HTML5标签
    如何开始使用bootstrap
    重新了解Java基础(三)-运行机制&HelloWorld
    重新了解Java基础(二)-Java的特性
    Java关键字之native
    重新了解Java基础(一)
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4421662.html
Copyright © 2011-2022 走看看