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:
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 |
|||||||||||||
|
|||||||||||||
Constraints |
|||||||||||||
- | H will be between 1 and 1,000,000,000, inclusive. | ||||||||||||
- | N will be between 1 and H, inclusive. | ||||||||||||
Examples |
|||||||||||||
0) | |||||||||||||
|
|||||||||||||
1) | |||||||||||||
|
|||||||||||||
2) | |||||||||||||
|
|||||||||||||
3) | |||||||||||||
|
|||||||||||||
4) | |||||||||||||
|
【題解】
非常複雜的遞推。
首先,這題有一個陷阱:不是所有的電梯間的距離都是相同的!(我中計了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 ; 1H=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;
}