Blogger homepage: Yu·Xiansheng
Column address: Detailed Explanation of Thousand Questions in Luogu
Table of contents
-------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------
Question description
One of the famous proofs in modern mathematics is Georg Cantor's proof that rational numbers are enumerable. He used the following table to prove this proposition:
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≤107).
-------------------------------------------------------------------------------------------------------------------------------
Output format
Item N in the table.
-------------------------------------------------------------------------------------------------------------------------------
Input and output samples
Input #1
7
Output #1
1/4
-------------------------------------------------------------------------------------------------------------------------------
Analysis:
update: Obviously, this kind of program is not the shortest. Many dalaodalao have pointed out in the comments, and the time complexity is not excellent, but at that time, I felt an inexplicable confidence . As for how to do it, the comment area also made it clearer. Now, so the comments don't need to provide ideas for suppressing the line anymore.
update: First we observe that the number in row ii and column jj is i/ji/j, which is the first thing to find.
Because the title requires a Z-shaped number
Let's look at the table in the title:
1/1,1/2,1/3 ……
2/1,2/2,2/3 ……
After the zigzag number (turn your head 45 degrees to the left):
First row: 1/1 (number 1)
Second row: 1/2 (No. 2) 2/1 (No. 3)
Third row: 1/3 (No. 6) 2/2 (No. 5) 3/1 (No. 4)
\uparrow↑ The observation method is easy to find that each line is 1 more than the previous line.
The while loop in the code is to determine which line and position it is after the number through loop enumeration.
(This question can be answered with or without this optimization, but the comments pointed out that my time complexity is not good enough, so I mention this optimization. If you don’t want to read it, you can just skip the content after the next dividing line.)
But in fact, we can directly conclude that the optimization time complexity is optimized from O(n) to O(1), so we must consider the sum of arithmetic sequences.
Formula: S=2n(an+a1)
Therefore, it is obvious that after Z-shaped sorting, the number n in the k-th row satisfies:
-------------------------------------------------------------------------------------------------------------------------------
C++ source code:
#include<cstdio>
int main()
{
int n;scanf("%d",&n);
int t=1,ans=0;//t是表示下一次跳到下一次的距离,ans是表示第几层
while(1)
{
if(n>t){n-=t;ans++;t++;}//printf("%d\n",ans);
else if(n==t&&ans%2==0){printf("1/%d",ans+1);break;}
//如果在n==t,并且为偶数层,就在第一行 第ans+1个
else if(n==t&&ans%2!=0){printf("%d/1",ans+1);break;}
//如果在n==t,并且为奇数层,就在第ans+1行 第一个
else if(n<t&&ans%2!=0){printf("%d/%d",ans+n-t+1,t-n+1);break;}
//如果在n<t,并且为奇数层,t-n+1表示该层最后一个往后走n-1步,ans+n-t+1示该层最后一个往上走t-1步
else if(n<t&&ans%2==0){printf("%d/%d",t-n+1,ans+n-t+1);break;}
// 如果在n<t,并且为偶数层,t-n+1表示该层最后一个往上走n-1步,ans+n-t+1示该层最后一个往后走t-1步
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
C++ source code 2:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i = 0, n, s = 0, x, y;//s:按整条斜线走过的格子的末尾编号
cin >> n;
while(s < n)//s >= n时,说明编号为n的格子在刚才加的第i斜线之中
{
i++;
s += i;
}
s -= i;//此时确定n在第i条斜线上
if(i % 2 == 1)//从i/1出发向右上遍历,找编号为n的格子
{
x = i, y = 1, s++;
while(s < n)//s == n时,x,y的值即为编号为n的格子的坐标
x--, y++, s++;
}
else//从1/i出发向左下遍历,找编号为n的格子
{
x = 1, y = i, s++;
while(s < n)//s == n时,x,y的值即为编号为n的格子的坐标
x++, y--, s++;
}
cout << x << '/' << y;
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
C++ source code 3:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i = 0, n, s = 0, x, y, l;
cin >> n;
while(s < n)//看第n格子是否在第i斜线上
{
i++;
s += i;
}
s -= i;
l = n-s;//在第i斜线数几个
if(i % 2 == 1)//从i/1出发
{
x = i+1-l;//i-x+1=l
y = l;
}
else//从1/i出发
{
x = l;//x-1+1 = l
y = i+1-l;//i-y+1=l
}
cout << x << '/' << y;
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
Java source code:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int position = scanner.nextInt();
int sum, end = 1;
while (true) {
sum = (1 + end) * end / 2;
if (position <= sum) break;
++ end;
}
sum -= position;
if (end%2 == 0) { // 偶数
// 大数在前
System.out.println((end-sum) + "/" + (1+sum));
} else { // 奇数
// 大数在后
System.out.println((1+sum) + "/" + (end-sum));
}
}
-------------------------------------------------------------------------------------------------------------------------------