[洛谷] [CF1B] 坐标转换

[洛谷] [CF1B] 坐标转换

题目链接:CF1B

题目描述

人们常用的电子表格软件(比如: Excel)采用如下所述的坐标系统:

第一列被标为 A,第二列为 B,以此类推,第 26 列为 Z。接下来为由两个字母构成的列号: 第 27 列为 AA,第 28 列为 AB ⋯ 在标为 ZZ 的列之后则由三个字母构成列号,如此类推。

行号为从 1 开始的整数。

单元格的坐标由列号和行号连接而成。比如,BC23 表示位于第 55 列 23 行的单元格。

有时也会采用被称为 RXCY 的坐标系统,其中 X 与 Y 为整数,坐标 (X,Y)直接描述了对应单元格的位置。比如,R23C55 即为前面所述的单元格。

您的任务是编写一个程序,将所给的单元格坐标转换为另一种坐标系统下面的形式。

输入

第一行一个整数 n \((<10^5)\) 表示将会输入的坐标的数量。

接下来 n 行,每行一个坐标。

注意: 每个坐标都是正确的。此外不会出现行号或列号大于 \(10^6\) 的单元格。

输出 n 行,每行一个被转换的坐标。

输出

n 行,每行一个被转换的坐标。

样例

2
R23C55
BC23
BC23
R23C55

题解

这里主要涉及到如何将 ABC 与其对应的列号互相转化的问题

我们可以将 ABC 视为26进制数,不过它有些特殊:

  • 例如,AAA 表示列号 26*26*1 + 26*1 + 1,这里26个数码分别对应 1,2,3,...,26

注意到我们没有对应为0的数码,这使将十进制转化为字母表示会有些困难:

RZ 对应 494 = 26*18+26,通常我们的做法是模进制取余数,但是这里模26会得到0,没有对应的数码,我们需要将模26得0的情况特判为Z

取余后的下一步操作是除进制,这里将26*18+26 除以 26下取整会得到 26*18+1,而我们需要得到 26*18才是正确的,因为末尾的26除26取整会留下1,而小于26的则不会,因此,上述情况还需要特判减去1。

于是,我们得到了两种数的转化算法:

  • ABC 转化为数字

int string_to_dig(string s){
    int ans = 0;
    for(auto i : s){
        ans*= 26;
        ans += s - 'A';
    }
    return ans;
}
  • 将数字转化为ABC
string mp = "ZABCDEFGHIJKLMNOPQRSTUVWXY";
string dig_to_string(int a){
    string ans = "";
    while(a){
        bool spec = a%26==0;
        ans.push_back(mp[a%26]);
        a/=26;
        if(a>0 && spec) --a;
    }
    return ans;
}

AC代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

//检查串所属的模式
// 0 BC12 1 R23C12
int mode(string ans){
    int r = 0;
    for(int i = 1;i<ans.size();i++){
        if(isdigit(ans[i-1])&&ans[i]>='A'&&ans[i]<='Z'){r=1;break;}
    }
    return r;
}
typedef pair<int,int> PII;

//将串变为通用的(x,y)坐标形式
PII toP(string s, int m){
    PII ans={0,0};
    if(m){
        for(int i = 1;i<s.size();i++){
            if(s[i] == 'C'){
                for(int j = i+1;j<s.size();j++){
                    ans.second *= 10;
                    ans.second += s[j]-'0';
                }
                break;
            }
            ans.first *= 10;
            ans.first += s[i]-'0';
        }
        return ans;
    }else{
        for(int i = 0;i<s.size();i++){
            if(isdigit(s[i])){
                ans.second *= 10;
                ans.second += s[i]-'0';
            }else{
                ans.first *= 26;
                ans.first += s[i]-'A'+1;
            }
        }
        swap(ans.first,ans.second);
        return ans;
    }
}
//快速找到数字对应的字母
string mp = "ZABCDEFGHIJKLMNOPQRSTUVWXY"; 
//坐标转变为对应模式将转变为模式的串
string mdt(PII pos, int m){
    string ans = "";
    int r = pos.first, c = pos.second;
    if(m){
        string ap="";
        while(c){
            bool z = c%26 ==0;
            ap.push_back(mp[c%26]);
            c/=26;
            if(c>0 && z)--c;
        }
        reverse(ap.begin(),ap.end());
        ans += ap;
        ap = "";
        while(r){
            ap.push_back(r%10+'0');
            r/=10;
        }
        reverse(ap.begin(),ap.end());
        ans += ap;
        return ans;
    }
    else{
        ans ="R"+to_string(r)+"C"+to_string(c);
        return ans;
    }
}

string s[100010];
int main(){
    int n;
    cin>>n;
    for(int i = 0;i<n;i++)cin>>s[i];
    for(int i = 0;i<n;i++){
        int m = mode(s[i]);
        cout<<mdt(toP(s[i],m),m)<<endl;
    }
    return 0;
}
上一篇:机器学习笔记


下一篇:.NET 5+ 中已过时的功能