【题目链接】
洛谷 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;
}