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;
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章