topcoder SRM495 div1 level3

Problem Statement

 When cat Taro went to an internship, he found a strange elevator in the office's skyscraper. The skyscraper contains 58 floors. The elevator is composed of 2 boxes and these 2 boxes move together. When the lower box stops at the x-th floor, the upper box always stops at the (x+1)-th floor. The lower box stops only on odd floors (1st, 3rd, 5th, ..., 57th). The upper box stops only on even floors (2nd, 4th, 6th, ..., 58th). He is very interested by this elevator, and he wants to compute the number of possible elevators composed of N boxes in a skyscraper of height H.



The elevators must satisfy the following conditions:
  • For each floor, exactly one box stops at that floor.
  • The distance between 2 boxes is an integer and never changes. More formally, for each pair of boxes (A,B), there must be some integer d such that box B always stops at the (x+d)-th floor when box A stops at the x-th floor. If the (x+d)-th floor doesn't exist, box A must not stop at the x-th floor.


Two elevators are different if the following is true. When the bottommost box is at the first floor, there exists an i such that a box is at the i-th floor in one elevator and no box is at the i-th floor in the other elevator. You are given two integers H and N. Return the number of possible elevators that have N boxes in a skyscraper of height H, modulo 1,000,000,007.
 

Definition

 
Class:StrangeElevator
Method:theCount
Parameters:int, int
Returns:int
Method signature:int theCount(int H, int N)
(be sure your method is public)
 
 
 

Constraints

-H will be between 1 and 1,000,000,000, inclusive.
-N will be between 1 and H, inclusive.
 

Examples

0) 
 
58
2
Returns: 2
The following two elevators are possible:
  • When the lower box stops at the 1st, 3rd, ..., 57th floor, the upper box stops at the 2nd, 4th, ..., 58th floor, respectively.
  • When the lower box stops at the 1st, 2nd, ..., 29th floor, the upper box stops at the 30th, 31st, ..., 58th floor, respectively.
1) 
 
1
1
Returns: 1
The only box always stops at the 1st floor.
2) 
 
9
3
Returns: 2
The following two elevators are possible:
  • When the lowest box stops at the 1st, the 4th and the 7th floor, the middle box stops at the 2nd, the 5th and the 8th floor, and the topmost box stops at the 3rd, the 6th and the 9th floor, respectively.
  • When the lowest box stops at the 1st, the 2nd and the 3rd floor, the middle box stops at the 4th, the 5th and the 6th floor, and the topmost box stops at the 7th, the 8th and the 9th floor, respectively.
3) 
 
120
12
Returns: 30
4) 
 
58585858
495
Returns: 0


【题解】

非常复杂的递推。

首先,这题有一个陷阱:不是所有的电梯间的距离都是相同的!(我中计了T—T)

我们看几个例子:

H=8,N=4

    4   ;     4     ;        4
    3   ;    4      ;        3
    2   ;     3     ;     4
    1   ;    3      ;     3
4       ;     2     ;        2
3       ;    2      ;        1
2       ;     1     ;     2
1       ;    1      ;     1
H=16,N=4

      4  ;           4  ;      4
      3  ;           3  ;     4
    4    ;         4    ;      3
    3    ;         3    ;     3
  4      ;           2  ;  4
  3      ;           1  ; 4
4        ;         2    ;  3
3        ;         1    ; 3
      2  ;   4          ;      2
      1  ;   3          ;     2
    2    ; 4            ;      1
    1    ; 3            ;     1
  2      ;   2          ;  2
  1      ;   1          ; 2
2        ; 2            ;  1
1        ; 1            ; 1
不难得出结论:

1:对于一个解,如果一列中号码连续的称为一个块,则块的大小是一个恒定的值L。

2:每个块之间的距离(即空档的大小)为L的倍数。

令F(H,N),G(H,N)分别为块的大小大于1和等于1的解的个数。

则有F(H,N)=sum(H/L,N/L),H%L==0,L>1;G(H,N)=F(H,H/N)

递归即可。

【代码】(给出topcoder的代码,使用map记录状态)

// map structures for the memoization
    map< pair<int,int>, int> gmemo;
    map< pair<int,int>, int> fmemo;
    
    
    // Implementation of the g function:
    int g(int H, int N)
    {
        map< pair<int,int>, int>::iterator q = gmemo.find( make_pair(H,N) );
        if ( q != gmemo.end() ) {
            return q->second;
        } else {
            int & res = gmemo[ make_pair(H,N) ];
            // The base case, if N is 1, there is only one
            // way to have a elevator of block length = 1.
            if ( N==1 )
            {
                res = 1;
                return 1;
            }
            res = f(H,H/N);
            return res;
        }
    }
    // Implementation of the f function:
    int f(int H, int N)
    {
        map< pair<int,int>, int>::iterator q = fmemo.find( make_pair(H,N) );
        if ( q != fmemo.end() ) {
            return q->second;
        } else {
            int & res = fmemo[ make_pair(H,N) ];
            res = 0;
            // Try all possible divisors of N, except 1:
            // 技巧:枚举约数的时候的循环
            for (int L=1; L <= N/L; L++) {
                if( N%L == 0 ) {
                    if (L>1) {
                        res = (res + g(H/L, N/L) ) % MOD;
                    }
                    if (L*L != N) {
                        res = (res + g(H/(N/L), L) ) % MOD;
                    }
                }
            }
            return res;
        }

    }
    int theCount(int H, int N)
    {
        if(H%N!=0) {
            return 0;
        }
        return (g(H,N) + f(H,N)) % MOD;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值