笔记——洛谷P1014Cantor表

笔记——洛谷P1014Cantor表

这道题有一个主要的坑点是z型排序是什么东西。所谓z字型排序,就是指对应一个正方形表格,以斜行为单位,依次遍历,其方向为从左上角开始,向右上,向左下,向右上,向左下(如图所示)。
排列方式
值得一提的是:最左上角的(1,1)方格作为起点是没有方向的(它所在的斜行仅有它自己),我是为了方便理解才描述成向右上的。
依照上图描述的排序方式,每格的编号如下:
每格子的编号
此外,考虑到题中给的cantor数表是三角形的,我们可以把图再裁剪掉一半,就是这样:
裁掉一半
把这张“编号图”重叠在数表上就可以清晰的看出每个数对应的编号了。

接下来开始研究每个位置的数的规律。他们具有以下规律:
x在第一行的奇数个时(i=1,j mod 2=1):a_x=(j^2-j)/2+j;
x在第一行的偶数个时(i=1,j mod 2=0):a_x=(j^2-j)/2+1;
x在第一列的奇数个时(j=1,i mod 2=1):a_x=(i^2-i)/2+1;
x在第一列的偶数个时(j=1,i mod 2=0):a_x=(i^2-i)/2+i;
x不在第1行或第1列,且在偶数斜行时((i+j) mod 2=1):该斜行最靠上(右)的数-两位置的横向距离(abs(j-j’));
x不在第1行或第1列,且在奇数斜行时((i+j) mod 2=0):该斜行最靠下(左)的数+两位置的横向距离(abs(j-j’));

根据以上规律可以计算所有位置的编号了。
此外,每一点上的数本身也是有规律的,这个规律比较好找,就是这一点的横坐标除以纵坐标(i/j);
最后就是查找输出了,虽然也可以直接暴力(我大概计算了一下,大概的范围是1<=i,j<=640),但是我才去了另一种方法,就是先缩小范围至某一斜行,再对该斜行进行遍历。

最后附上AC代码:

#include<iostream>
using namespace std;
int f(int i,int j)
{
    int ans=0;
    if (i==1&&j%2==1)
    {
        ans=(j*j-j)/2+j;
    }
    else if (i==1&&j%2==0)
    {
        ans=(j*j-j)/2+1;
    }
    else if (j==1&&i%2==1)
    {
        ans=(i*i-i)/2+1;
    }
    else if (j==1&&i%2==0)
    {
        ans=(i*i-i)/2+i;
    }
    else if ((i+j)%2==1)
    {
        int tmp=j;
        while (i!=1)
        {
            i--;
            j++;
        }
        if (tmp-j>0)
        {
            ans=f(i,j)+(tmp-j);
        }
        else
        {
            ans=f(i,j)+(j-tmp);
        }
    }
    else if ((i+j)%2==0)
    {
        int tmp=i;
        while (j!=1)
        {
            i++;
            j--;
        }
        if (i-tmp>0)
        {
            ans=f(i,j)+(i-tmp);
        }
        else
        {
            ans=f(i,j)+(tmp-i);
        }
    }
    return ans;
}
int main()
{
    int n,m=0;
    int a;
    int i,j;
    cin>>n;
    for (a=1;m<n;a++)
    {
        m+=a;
    }
    a=a-1;
    for (i=a,j=1;j<=a;i--,j++)
    {
        if (f(i,j)==n)
        {
            cout<<i<<"/"<<j<<endl;
            break;
        }
    }
    return 0;
}

-END-

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值