Cantor表

Cantor表 1999年NOIP全国联赛普及组

时间限制: 1 s
空间限制: 128000 KB
题目等级 : 白银 Silver
题解
题目描述 Description
现代数学的著名证明之一是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,…

输入描述 Input Description
整数N(1≤N≤10000000)
输出描述 Output Description
表中的第N项
样例输入 Sample Input
7
样例输出 Sample Output

1/4


1.根据表面规律求第n个Cantor数

#include <iostream>
#include <stdio.h>
using namespace std;

int main(){
    int n;
    while(~scanf("%d", &n)){
        int i = 0, j = 0, cnt = 0;
        while(cnt < n){
            while((i + j) % 2 == 0 && i != 0){
                cnt++;
                if(cnt == n)
                    cout << i + 1 << '/' << j + 1 << endl;
                i--; j++;
            }
            while((i + j) % 2 == 1 && j != 0){
                cnt++;
                if(cnt == n)
                    cout << i + 1 << '/' << j + 1 << endl;
                i++; j--;
            }

            if(i == 0){
                cnt++;
                if(cnt == n)
                    cout << i + 1 << '/' << j + 1 << endl;
                if(j % 2 == 0)
                    j++;
                else{
                    i++; j--;
                }
            }
            if(j == 0){
                cnt++;
                if(cnt == n)
                    cout << i + 1 << '/' << j + 1 << endl;
                if(i % 2 == 1)
                    i++;
                else{
                    i--; j++;
                }
            }
        }
    }
}
2.找逻辑规律

根据题目给出的Cantor图可以看出,每一个斜行,分母和分子的数值都是有规律可循的,当分子分母之和(或斜行数)为奇数时,分母从右上递减到左下,分子则是从右上递增到左下,当分子分母之和(或斜行数)为偶数时,分母从左下递增到右上,分子则是从左下递减到右上,而分子或分母的最大值刚好为其所处的斜行数,把这个直角三角形扳正后可以看出,有点类似于杨辉三角或二叉树的顺序存储。

假设题目要求第n个Cantor数,则先要知道其处于第几斜行,通过一个while循环来得到其所处的第k行,而前k行(包括k行)共有Cantor数S = n * (n + 1) * (1 / 2)个,用S减去n在加上1即得到第n个Cantor数的分母S - n + 1,则其分子为第k行的Cantor总数k减去分母再加1,即k - (S - n + 1) + 1,最后格式化输出即可。

#include <iostream>
#include <stdio.h>
using namespace std;

int main(){
    int n;
    while(~scanf("%d", &n)){
        int S = 0, k = 0;
        while(S < n){
            k++;
            S += k;
        }
        if(k & 1)
            printf("%d/%d\n", S - n + 1, (k + 1) - (S - n + 1));
        else
            printf("%d/%d\n", (k + 1) - (S - n + 1), S - n + 1);
    }
}
或者不用再去设置一变量S,直接对n进行递减即可。

#include <iostream>
#include <stdio.h>
using namespace std;

int main(){
    int n;
    while(~scanf("%d", &n)){
        int k = 0;
        while(n > k){
            k++;
            n -= k;
        }
        if(k & 1)
            printf("%d/%d\n", k + 1 - n, n);
        else
            printf("%d/%d\n", n, k + 1 - n);
    }
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值