[NOIP1999 Popularization Group] Cantor table
Title description:
One of the famous proofs of modern mathematics is Georg Cantor's proof that the rational numbers are enumerable. He proves this proposition with the following table:
1/1 , 1/2 , 1/3 , 1/4, 1/5, …
2/1, 2/2 , 2/3, 2/4, …
3/1 , 3/2, 3/3, …
4/1, 4/2, …
5/1, …
…
We number each item in the table above in a zigzag. The first item is 1/1, then 1/2, 2/1, 3/1, 2/2, ...
Input format:
Integer N (1 <= N <= 10^7).
Output format:
Nth item in the table.
Example #1:
Sample input #1:
7
Sample output #1
1/4
Ideas:
Algorithm 1: Simulation
Simulate, enumerate one by one according to the meaning of the topic
Time complexity O(n), you can pass this question n≤10^7.
Algorithm 2: Enumeration
Each slash that finds the zigzag can be enumerated quickly, that is, enumeration
1/1 , 1/2 , 3/1 , 1/4 , 5/1 , 1/6... Find the slash where the required nth item is located, and then enumerate or calculate the answer one by one
Time complexity O(√n), can pass n≤10^14
Algorithm 2.2: Enumeration Simplification
Enumerate which row the nth item is in, and calculate the answer, which is easier to write than Algorithm 2,
The time complexity is the same as Algorithm 2
Algorithm 3: Divide
It is found that the i-th slash (that is, all items where the sum of the numerator and denominator = i+1) contains each item from i*(i-1)/2+1 to i*(i+1), so it can be divided into two The sum of the numerator and denominator, and then directly calculate the nth item according to the parity of the sum of the numerator and denominator
Time complexity O(㏒₂n), can pass n≤10^18, plus high-precision can pass n≤10^1000
Binary algorithm code:
#include<iostream>
#include<cmath>
using namespace std;
int main(){
long long l=1,r,mid,n,a;
cin>>n;
r=n;
while(l<r){
mid=(l+r)/2;
if(mid*(mid+1)/2<n)
l=mid+1;
else
r=mid;
}
a=n-l*(l-1)/2;
if(l%2==0)
cout<<a<<'/'<<l+1-a;
else
cout<<l+1-a<<'/'<<a;
return 0;
}
Of course, the simplest thing is to push directly from "mathematics", and the complexity of O(1) takes off directly, so let's push it directly!
Algorithm 4: Mathematical direct push
The known data is the first one.
The triangle drawn in an obvious Z shape, the number of rows from the upper left to the lower right is an arithmetic sequence starting from 1 with a tolerance of 1 . So using the summation formula , if the number of rows is set to be:
Therefore we set such that
According to the incrementality of the established function , we know that
Therefore, by finding the root formula and then rounding up, the number of rows can be calculated in O(1) time complexity.
Which is
Next, ask for the specific location of the source in the current line, which is very easy, you only need to know how many there are in that line: the obvious ones
So what is required is the first one of that line .
Next is a Cantor form method for knowing the number of rows + the number :
For all individuals in row a, there are ("/" on the left) + ("/" on the right)
At the same time ,
The output should be:
<u>(_number_ )/(a+1- _number_ )</u>
<u>The rest of the "/" should be reversed. </u>
The above is O(1) ( in fact, it should not be much faster than two points, which is equivalent to letting the system make three points ) to solve this problem. Since it is a mathematical calculation, the code will not be posted, it is meaningless.
Summarize:
The topic of this question is very simple and can be solved with a very simple algorithm, but we can draw inferences from one instance, think more deeply, and think of a more powerful, more efficient and faster algorithm.