3600: 计数-训练套题T2T3

Memory Limit:128 MB Time Limit:1.000 S
Judge Style:Text Compare Creator:
Submit:0 Solved:1

Description

3.计数 [DigitalCounter.pas/ c/cpp]

【问题描述】

我们有一个N位数字的电子表,当时间到达10^N-1时,下一秒就归0。下面我们给出数字0 9的模拟图。

    +   +---+   +---+   +   +   +---+
    |       |       |   |   |   |
    +   +---+   +---+   +---+   +---+
    |   |           |       |       |
    +   +---+   +---+       +   +---+
 
+---+   +---+   +---+   +---+   +---+
|           |   |   |   |   |   |   |
+---+       +   +---+   +---+   +   +
|   |       |   |   |       |   |   |
+---+       +   +---+       +   +---+

对于每个数字,相邻两个+之间会有一根电子管,当显示该数字时,这些电子管就会发亮。如上图所示:数字09,它们的电子管数量分别是:62 5 5 4 5 6 3 7 5

设现在的时刻是X, 那么可以算出该时有多少根电子管是亮的。比如:现在时刻是:99,那么共有5 + 5= 10根电子管是亮的。假如从现在时刻开始,再过Y秒后,时刻显示为Z, 我们的问题是:求最小的Y,使得时刻Z发亮的电子管数量与时刻X发亮的电子管数量相等。如:现在X = 99 ,那么再过Y = 5 秒后, 时刻变成了Z = 04, 而时刻Z发亮的电子管数量 = 6 + 4 = 10。于是Y = 5就是你要求的数。

【输入数据】

第一行:一个整数N,表示电子表是10^N进制的。1 <= N <= 15

对于30%数据,N < 7.

第二行:一个整数X, 表示现在的时刻,可能有前导0XN位数字。

【输出数据】

一行:最小的整数Y, 表示从现在X时刻开始,再过Y秒,得到的时刻Z发亮的电子管数量与时刻X发亮的电子管数量相等。

【输入样例】

3

007

【输出样例】

11

【样例说明】

因为数字0076+6+3 =15根电子管发亮,所以过11秒后,电子表显示数字018时,才能满足发亮的电子管数量相等。018时刻发亮的电子管数量 = 6 + 2 + 7 = 15

HINT

计数 DigitalCounter

n       数字09,它们的电子管数量分别是:62 5 5 4 5 6 3 7 5

n       设现在的时刻是X, 那么可以算出该时有多少根电子管是亮的。

n       假如从现在时刻开始,再过Y秒后,时刻显示为Z, 我们的问题是:求最小的Y,使得时刻Z发亮的电子管数量与时刻X发亮的电子管数量相等。

n       统计一个数X有多少根电子管是亮的很容易

n       如果每次1秒增加,模拟现实过程,则因为最多有15位数,显然要超时。(1 <= N <= 15)

n       怎样做呢?
二分法?
找规律?
递推或DP

n       没有单调性,不能二分。

n       找规律也好像不可能。

n       递推之类的?
不能按时间,那样会超时
按什么呢?

n       题目中的其它可能变量
1
)数X的位数len---15
2
)亮的电子管个数light---也不大<=15*7

n       设函数f(a)表示数a的有多少电子管是亮的。

n       初始数是X,则要找Y,使f(Y)=f(X)

n       假设Y>X,则Y尽量小:
1
)开头数dig尽量小
3
)开头数也一样?比较第二位数
…..

n       问题与长度、开头数、电子管数的判断有关。

n       工具函数g( len,  light) 判断问题。(没dig?

n       g( len, light) 函数推算:

 

n       g(len, light) = or  g(len-1,light-f(i) )  i=0~9


即开头数字是0~9中任何一个成立都可以。

 

n       显然个g数组比较容易DP出来。

n       g( len, light) 函数推算:

 

n        g[0,0]:=true;

n            for i:=1 to N do

n              for j:=1 to 120 do

n                 for k:=0 to 9 do

n                   g[ i,j ] := g[i,j] or g[i-1, j - c[k] ];

n       有了g( len, light) 要求最接近XY

n       先看Y>X的情况:

n       考察例子:X =98675  f(x) = 26

  1)先看最后一位:

   y = 98676~98679  看有没有f(y)=26

  2)再看第二位:

   y =9868*~9869*   如果有f(y)=26,再定*

  3)同理看 y=987**~989**

n       即先从低位到高位,从小到大,先看能否有一个类似: 988**成立,再推算最小的数**

n       什样推算?
例如: 988**中,如果**还要7个电子管发亮,则只要从高位到低位试,看:0*~9*那些可行,比如1*可行,则看*中电子管为7-f(1)=7-2=5的,即0~9中选最小的电子管是5的数字2即可。最后答案为98812

n       Y<=X的情况只要推算最小的*****即可。

n       function getBig( var len, dig :integer) :boolean;

n       begin

n             fx:=0;

n             for i:=1  to N do                   //从低位到高位

n             begin

n                 fx := fx + c[ d[ i ]  ];          //X的前i位电子管数

n           for j:=d[ i ]+1 to 9 do       //比原Xi位大的数,从小到大

n             if (fx>=c[j]) and (g[ i-1, fx - c[ j ] ] ) then

n                  begin  len:=i; dig:=j;  exit( true);           //找到最小的

n                       end;

n             end;

n             exit (false);

n       end;

n       procedure getMin(len, fx:integer);

n       begin

n           for i:=len downto 1 do    //从高位到低位

n           begin

n                 for j:=0 to 9 do        //尽量小数字

n              if  (fx>=c[j]) and (g[ i -1, fx - c[j] ] ) then

n                       break;

n           ans[ i ] := j;

n           fx := fx-c[j];               //后面还有多少电子管

n           end;

n       end;

procedure calc();

var  len, dig :integer;

begin

     ans:=d;

     if getBig(len,dig) then

     begin                  //如果在>XY,即不“环绕”

          ans[len]:=dig;

          getMin(len-1, fx-c[dig]);

         yy:=0;

         for i:=N downto 1 do yy := yy*10 + ans[i];

         Y:= yy - X;

     end

     else  begin               //如果“环绕”了

              getMin(N, fx);   //求一个尽量小的     

             yy:=0; Y:=1;

            for i:=N downto  1 do begin

                yy := yy*10 + ans[i];

                 Y := Y*10;    //10^N

            end;

            Y:= Y-X + yy;

     end;

end;