洛谷 P1014 [NOIP1999 普及组] Cantor 表 | OpenJudge NOI 2.1 8760:Cantor表

【题目链接】

洛谷 P1014 [NOIP1999 普及组] Cantor 表
OpenJudge NOI 2.1 8760:Cantor表

【题目考点】

1. 二维数组
2. 找规律
3. 两下标间元素数量

数组中下标a到下标b间元素个数n(包括下标a和下标b的元素)
n = b-a+1

【解题思路】

先为每条斜线编号
在这里插入图片描述
假设有一个焦点位置不断移动,每移动一次,编号加1。
根据题目中给定的编号规律,可以得知:

  • 当i为奇数时:焦点从i/1出发,从左下到右上移动到1/i
  • 当i为偶数时:焦点从1/i出发,从右上到左下移动到i/1

第1条斜线上有1/1,1个格子
第2条斜线上有2/1,1/2两个格子

第i条斜线上有i个格子

要想求编号为n的格子的坐标,可以先求数到n时,已经数完了多少条完整的斜线。
假设有位置s,初值为0,每次加一条斜线长度的数值。s+=1后,s是第一条斜线的末尾格编号;s+=2后,s是第二条斜线的末尾格编号;s+=i后,s是第i条斜线末尾格编号。
如果s<n,s就不断增加,直到s+=i后,发现s>=n,这说明n就在刚刚加的第i条斜线上。
执行s -= i。
此时:s为上一条斜线的末尾位置。n-s为 n是第i条斜线上的第几个格子。
后面步骤分两种解法

解法1:移动焦点
  • i为奇数时,从i/1出发,i/1编号为s+1,从左下到右上移动,直到找到编号为n的格子,输出该格子坐标。
  • i为偶数时,从1/i出发,1/i编号为s+1,从右上到左下移动,直到找到编号为n的格子,输出该格子坐标。
解法2:坐标计算

记:l = n-s,表示在第i斜线需要数几个格子

  • i为奇数时,从i/1出发,i/1为第1个格子,从左下向右上看,第l个格子的编号即为n。设编号为n的格子的坐标为:nx,ny,那么根据两下标间距离公式n=b-a+1有:
    i - nx + 1 = l
    ny - 1 + 1 = l
    得到:
    nx = i + 1 - l
    ny = l
  • i为偶数时,从1/i出发,1/i为第1个格子,从右上向左下看,第l个格子的编号即为n。设编号为n的格子的坐标为:nx,ny,那么根据两下标间距离公式n=b-a+1有:
    nx - 1 + 1 = l
    i - ny + 1 = l
    得到:
    nx = l
    ny = i + 1 - l

【题解代码】

解法1:移动焦点
#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;
}
解法2:坐标计算
#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值