[普及][NOIP1999 普及组] Cantor 表

本文介绍了Cantor数表的构造和如何按照Z字形给数表中的项编号。针对NOIP1999普及组的一道题目,解释了解题思路和AC代码,包括直接模拟和数学优化方法。
摘要由CSDN通过智能技术生成

题目描述

现代数学的著名证明之一是 Georg Cantor 证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

1/11/1 , 1/21/2 , 1/31/3 , 1/41/4, 1/51/5, …

2/12/1, 2/22/2 , 2/32/3, 2/42/4, …

3/13/1 , 3/23/2, 3/33/3, …

4/14/1, 4/24/2, …

5/15/1, …

我们以 Z 字形给上表的每一项编号。第一项是 1/11/1,然后是 1/21/2,2/12/1,3/13/1,2/22/2,…

输入格式

整数�N(1≤�≤1071≤N≤107)。

输出格式

表中的第 �N 项。

样例 #1

样例输入 #1

7

Copy

样例输出 #1

1/4

Copy

题解1

解题思路

可以把上面的数表右转45度,成一金字塔形状,如下所示:

1/1

2/1 1/2

3/1 2/2 1/3

4/1 3/2 2/3 1/4

…… …… …… ……

该金字塔第1行有1个数,第2行有2个数,…,第i行有i个数。并且第i行上的i个分数的分子从i ~ 1,分母从1 ~ i,即第1个分数为i/1,最后一个分数为1/i。

为输出数表中的第N项,先需计算这一项在第几行。设第N项在x行,由于前x-1行共有1+2+3+…+(x-1)项,前x行有1+2+…+x项,因此有:

可以用一个循环计算第n项所在的行数,如下:

for (i=1; i*(i+1)/2<n; i++);

Copy

循环退出后,i*(i+1)/2刚好大于或等于n,因此,i就是第n项所在的行。

第n项在第i行中属于第几项又可以计算出来,公式为:

 即n减去前i-1行中的全部项数。

由于是以z字型方法给数表的每项编号,因此当行号为奇数时,编号从左往右进行;当行号为偶数时,编号从右往左进行。

这样,当i为奇数时,第i行的第k项为(i+1-k)/(k);当i为偶数时,第i行的第k项为(k)/(i+1-k)。

AC代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int i, x, n;
    cin >> n;
    for (i = 1; i * (i + 1) / 2 < n; i++); //不要忘记这个分号!
    x = n - (i * (i - 1) / 2);
    if (i % 2 != 0)
       printf("%d/%d\n", i + 1 - x, x);
    else
       printf("%d/%d\n", x, i + 1 - x);
    return 0;
}

题解2 

思路1

这道题我很久之前做过,那时我还是萌新时代,啃了10天,然后终于AC了。

我的思路很简单,直接暴力模拟(这道题就是考模拟,1≤�≤1071≤n≤107),我的模拟就是模拟 �−1n−1 次Z字形移动,判断是否到边上和奇数偶数边,费了老死劲了,才搞出来。

#include <bits/stdc++.h>
using namespace std;
int n, x = 1, y = 1;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n - 1; i++)
    {
        if ((x + y) % 2 == 0 && y == 1)
        {
            // 向右
            x++;
        }
        else if ((x + y) % 2 == 1 && x == 1)
        {
        
  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值