【SCOI 2009】Windy数

1026: [SCOI2009]windy数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 274  Solved: 130
[Submit][Status][Discuss]

Description

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

Input

  包含两个整数,A B。

Output

  一个整数。

Sample Input

【输入样例一】      【输入样例二】
  1 10        
  25 50

Sample Output

【输出样例一】      【输出样例二】
  9            
20 


【数据规模和约定】
  20%的数据,满足 1 <= A <= B <= 1000000 。
  100%的数据,满足 1 <= A <= B <= 2000000000 。

=====================================================================================================

  如果我当年考SCTSC的话,我看到题肯定马上叫监考,问他限制代码规模多少k……

  不会显然可以打表,限制代码长度的话可以小于10000000的暴力,大于10000000的打表……其实,Cena的代码大小限制根本就是摆设,用Ubuntu的话另当别论了……

  咳咳……说正经的……

  这个题我觉得是SCTSC Day1里面比较水的题……但是不怎么容易得分,毕竟数字统计这类的题细节是需要多加注意的。

  显然1..100000(好多0) 的可以按位预处理递推得到。

    f[i,j]表示位数为i,最高位为j范围内Windy数的个数。

    初始状态:f[1,i]=0  ,  i∈[0,9]

    f[i,j]=∑(f[i-1,k]) ,  |j-k|≥2

  然后……一位一位地找就行了……

  但是要注意,一个数的个位数处理与其他位置的数处理有所不同……

/**************************************************************
    Problem: 1026
    User: Delostik
    Language: Pascal
    Result: Accepted
    Time:0 ms
    Memory:248 kb
****************************************************************/
 
program SCOI_2009_WindyNumber;
var BASE:Array[1..10]of longint;
    f:array[1..10,0..9]of longint;
    a,b:longint;
 
procedure init;
var i,j,k:longint;
begin
     BASE[1]:=1;
     for i:=2 to 10 do BASE[i]:=BASE[i-1]*10;
     readln(a,b);
     for i:=0 to 9 do f[1,i]:=1;
     for i:=2 to 10 do
         for j:=0 to 9 do
             for k:=0 to 9 do
                 if abs(j-k)>=2 then inc(f[i,j],f[i-1,k]);
end;
 
function count(n:longint):longint;
var w,i,j,cur,pre,last:longint;
begin
     if n=0 then exit(0);
     count:=0;
     w:=10;
     while BASE[w]>n do dec(w);
     for i:=1 to w-1 do
         for j:=1 to 9 do
             inc(count,f[i,j]);
     cur:=n div BASE[w];
     for i:=1 to cur-1 do inc(count,f[w,i]);
     n:=n mod BASE[w];
     pre:=cur;
     for i:=w-1 downto 1 do
         begin
              cur:=n div BASE[i];
              if i<>1 then
                 begin
                      for j:=0 to cur-1 do
                          if abs(pre-j)>=2 then inc(count,f[i,j]);
                 end
              else
                  for j:=0 to cur do
                      if abs(pre-j)>=2 then inc(count,f[i,j]);
              if abs(cur-pre)<2 then exit;
              pre:=cur;
              n:=n mod BASE[i];
         end;
end;
 
procedure solve;
begin
     writeln(count(b)-count(a-1));
end;
 
begin
     init;
     solve;
end.

原文地址:https://www.cnblogs.com/Delostik/p/2015031.html