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