P1014 Cantor表
漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P1014
题目描述
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:
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 …
… 我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…
输入输出格式
输入格式:
整数N(1≤N≤10000000)
输出格式:
表中的第N项
输入输出样例
输入样例#1: 复制
7
输出样例#1: 复制
1/4
// luogu-judger-enable-o2 //Cantor表的二分log做法 //可以知道,第i个对角线上一共有i个数 //那么,前i条对角线上就有1+2+3+4+...+i-1+i个数 //也就是i + (1 + i-1) + (2 + i-2) + (3 + i-3) + ((i/2)-1 + (i/2)+1)+ i/2个数 //也就是 i*((i/2)-1) + i + i/2个数 //把i提出来,就变成了 i*((i-2+2+1)/2) //也就是 i*(i+1)/2 //所以,二分一个mid,如果mid*(mid-1)/2<n的话 //说明在第i条斜线之后,否则在之前或在第i条斜线上 //找到了第n个数所处的斜线之后,再找它在斜线上的位置 //奇数斜线从左下往右上走,偶数斜线从右上往左下走 //这条斜线的之钱有第i*(i-1)/2个数, //所以我们要找的就是这条线上第n - i*(i-1)/2个数 //让a = n - i*(i-1)/2 //奇数线就输出i-a+1 / a //偶数线就输出 a / i-a+1 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n; int main() { scanf("%d",&n); int l=1,r=n,mid; while(l<r) { mid=l+r>>1; if(mid*(mid+1)/2<n) l=mid+1; else r=mid; } int a=n-r*(r-1)/2; if(r&1) printf("%d/%d",r-a+1,a); else printf("%d/%d",a,r-a+1); return 0; }