Please consider the following:
- Input N
- Output N
- If N = 1, then ends
- If N is an odd number, then N = 3*N + 1
- Else, N = N/2
- GOTO 2
For example, given the input 22, the resulting sequence is 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1.
The algorithm is expected to terminate for any integer (when it prints 1). While this algorithm is simple, whether the conjecture holds true for all N (0 < N <= 1,000,000) cannot be known. However, it has been verified that the conjecture holds true for all N (0 < N <= 1,000,000).
Given an input N, through the above algorithm, we can obtain a sequence of numbers (ending with 1). The length of this sequence is called the Cycle Length of N. As mentioned above, for example: the Cycle Length of 22 is 16.
The question is: For any two integers i and j, we want to know the maximum Cycle Length generated by the numbers between i and j (inclusive).
Sample Inputs/Outputs
Sample Input(s) | Sample Output(s) |
---|---|
EOF inputs: each test case consists of a pair of integer data, i and j. (0 < i, j <= 1,000,000) | The output should include i and j, along with "the maximum total Cycle Length of the 3n+1 Problem from i to j." |
1 10 100 200 201 210 900 1000 | 1 10 20 100 200 125 201 210 89 900 1000 174 |
Thought Process
This problem can be approached by creating a table from 1 to 1,000,000, but running the 3N+1 function 1,000,000 times can still be time-consuming. However, it's noticeable that when N is divisible by 2, the return value of its 3N+1 function will be the return value of N/2 plus 1. Utilizing this fact, we only need to evaluate the "odd numbers" from 1 to 1,000,000.
To optimize further, besides creating a table for the return values of the 3N+1 function, we also need to construct a segment tree for the maximum values from i to j. Then, we can create a query function to compute the maximum value from i to j. This approach ensures that the solution won't result in Time Limit Exceeded (TLE). Additionally, i can be greater than j in the test cases, in which case we need to swap(i, j). However, when outputting the results, we still need to adhere to the original order. This detail needs attention.
Sample Code-ZeroJudge D712: The 3n + 1 problem
#include <iostream>
using namespace std;
int MAP[1000005] = {};
int a, b, maxx = -1;
int tree[3000000] = {};
void initial() {
for(int i = 2; i < 1000001; i++)
{
long long int c = i;
int count = 1;
if(i % 2 == 0)
{
MAP[i] = MAP[i>>1]+1;
continue;
}
while(c >= i)
{
if(c % 2)
{
c = c*3+1;
c >>= 1;
count+=2;
}
else
{
c = c>>1;
count++;
}
}
MAP[i] = count + MAP[c]-1;
}
}
void build(int l, int r, int index)
{
if (l == r)
{
tree[index] = MAP[l];
return;
}
build(l, (l+r)/2, (2*index)+1);
build(((l+r)/2)+1, r, (2*index)+2);
tree[index] = max(tree[(index*2)+1], tree[(index*2)+2]);
return;
}
void query (int l, int r, int index)
{
if (a <= l && r <= b)
{
maxx = max(maxx, tree[index]);
return;
}
if (l == r)
{
maxx = max(maxx, tree[index]);
return;
}
int half = (l+r)/2;
if (a <= half)
{
query(l, half, (index*2)+1);
}
if (b > half) query (half+1, r, (index*2)+2);
}
int main() {
cin.sync_with_stdio(0);
cin.tie(0);
cout.sync_with_stdio(0);
cout.tie(0);
MAP[1] = 1;
initial();
build(1, 1000000, 0);
while (cin >> a >> b)
{
int c = a;
int d = b;
if (a > b) swap(a, b);
maxx = -1;
query(1, 1000000, 0);
cout << c << " " << d << " " << maxx << "\n";
}
}
//ZeroJudge D712
//Dr. SeanXD