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;
}
原文地址:https://www.cnblogs.com/lovewhy/p/8666096.html