Timus 1013. K-based numbers. Version 3

Timus 1013. K-based numbers. Version 3 要求计算出不包括相邻的零的 N 位 K-进制数共有多少个。

1013. K-based numbers. Version 3

Time Limit: 2.0 second
Memory Limit: 16 MB

Let’s consider K-based numbers, containing exactly N digits. We define a number to be valid if its K-based notation doesn’t contain two successful zeros. For example:
  • 1010230 is a valid 7-digit number;
  • 1000198 is not a valid number;
  • 0001235 is not a 7-digit number, it is a 4-digit number.
Given two numbers N and K, you are to calculate an amount of valid K based numbers, containing N digits.
You may assume that 2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 1800.

Input

The numbers N and K in decimal notation separated by the line break.

Output

The result in decimal notation.

Sample

inputoutput
2
10
90

解答如下:

 1  using  System;
 2 
 3  namespace  Skyiv.Ben.Timus
 4  {
 5     //   http://acm.timus.ru/problem.aspx?space=1 &num=1013
 6     sealed   class  T1013
 7    {
 8       static   void  Main()
 9      {
10         int  n  =   int .Parse(Console.ReadLine()), i  =   2 ;
11         int  k  =   int .Parse(Console.ReadLine())  -   1 ;
12        BigInteger m  =   0 ;
13         for  (BigInteger p  =   1 , q  =  k; i  <=  n; i ++ , p  =  q, q  =  m) m  =  (p  +  q)  *  k;
14        Console.WriteLine(m);
15      }
16    }
17 
18     sealed   class  BigInteger
19    {
20       int [] digits  =   new   int [ 1800 ];
21 
22       public  BigInteger( int  n)
23      {
24        digits[ 0 =  n;
25         if  (digits[ 0 >   9 ) Format();
26      }
27 
28       public  BigInteger(BigInteger x)
29      {
30        Array.Copy(x.digits, digits, digits.Length);
31      }
32 
33       public   static   implicit   operator  BigInteger( int  x)
34      {
35         return   new  BigInteger(x);
36      }
37 
38       public   static  BigInteger  operator   + (BigInteger x, BigInteger y)
39      {
40        BigInteger z  =   new  BigInteger(x);
41         for  ( int  i  =  x.digits.Length  -   1 ; i  >=   0 ; i -- ) z.digits[i]  =  x.digits[i]  +  y.digits[i];
42        z.Format();
43         return  z;
44      }
45 
46       public   static  BigInteger  operator   * (BigInteger x,  int  y)
47      {
48        BigInteger z  =   new  BigInteger(x);
49         for  ( int  i  =  x.digits.Length  -   1 ; i  >=   0 ; i -- ) z.digits[i]  =  x.digits[i]  *  y;
50        z.Format();
51         return  z;
52      }
53 
54       void  Format()
55      {
56         for  ( int  quotient  =   0 , i  =   0 ; i  <  digits.Length; i ++ )
57        {
58           int  numerator  =  digits[i]  +  quotient;
59          quotient  =  numerator  /   10 ;
60          digits[i]  =  numerator  %   10 ;
61        }
62      }
63 
64       public   override   string  ToString()
65      {
66         int  n  =  digits.Length  -   1 ;
67         while  (n  >=   0   &&  digits[n]  ==   0 ) n -- ;
68         if  (n  <   0 return   " 0 " ;
69         char [] cs  =   new   char [n  +   1 ];
70         for  ( int  i  =  n; i  >=   0 ; i -- ) cs[i]  =  ( char )(digits[n  -  i]  +   ' 0 ' );
71         return   new   string (cs);
72      }
73    }
74  }

这道题要求计算出不包括相邻的零的 N 位 K-进制数共有多少个。这里 2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 1800。

我们还是开始找规律吧。右图是 K = 4,N = 3 的情况。

我们用 Mn 来表示 n 位 K-进制数的数量。从右图中可以看出:

M2 = 12, M3 = 45

经过仔细观察,我们假设:

M0 = 1, M1 = 3

然后再经过认真分析,我们得到以下规律:

M0 = 1, M1 = K - 1,  Mn = (K - 1) * (Mn-1 + Mn-2)  (n > 1)

在递推公式 Mn = (K - 1) * (Mn-1 + Mn-2) 中:

系数 K - 1 代表 K-进制数的最高位从 1 到 K - 1

Mn-1 代表次高位不为零的情形

Mn-2 表示次高位为零的情形

然后,对于 K = 2、K = 3 在 N 比较小的情况下验证了这个规律。

既然有了递推公式,写出相应的程序自然易如反掌。

但是,要注意,当 K = 10,N = 1790 时,M1790 接近 101790,所以要使用 BigInteger 类来进行计算。

实际上,这个问题共有三姐妹,分别是:

1009. K-based numbers时间限制:1.0 秒2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 18
1012. K-based numbers. Version 2时间限制:1.0 秒2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 180
1013. K-based numbers. Version 3时间限制:2.0 秒2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 1800

当然,上面的程序也完全适用于 Timus 1009 和 Timus 1012。

另外,对于 Timus 1009,把上面程序 Main() 方法中的第 12 和 13 行中的 BigInteger 改为 int 也完全没有问题。因为 int.MaxValue = 2,147,483,647,而我们有:

NKM
1621,597
153
2,781,184
144
104,879,772
135
661,766,144
126
1,413,765,625
117
1,434,392,064
108
837,677,687
9
9
317,882,368
8
10
85,096,170

从上表中可以看出,Timus 1009 的输出绝对不会大于 1,434,392,064,所以使用 int 是安全的。

下面是这个程序的运行情况:

其中 ID 为 2147015 的记录就是把 BigInteger 改为 int 后的程序的运行结果,运行时间为 0.093 秒。这个结果有点奇怪,因为她比使用 BigInteger 的程序的运行时间 0.078 秒还要大。因为一般来说,用 int 进行运算应该比 BigInteger 快才对。

修改后的程序如下所示:

 1  using  System;
 2 
 3  namespace  Skyiv.Ben.Timus
 4  {
 5     //   http://acm.timus.ru/problem.aspx?space=1 &num=1009
 6     sealed   class  T1009
 7    {
 8       static   void  Main()
 9      {
10         int  m  =   0 , n  =   int .Parse(Console.ReadLine());
11         int  k  =   int .Parse(Console.ReadLine())  -   1 ;
12         for  ( int  i  =   2 , p  =   1 , q  =  k; i  <=  n; i ++ , p  =  q, q  =  m) m  =  (p  +  q)  *  k;
13        Console.WriteLine(m);
14      }
15    }
16  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值