1 条题解
-
0
思路
题意:每次给出一个长度为 10、只含小写字母的串 和整数 ,把“合法刻印”按字典序从小到大排列(
aaaaaaaaaa最小、zzzzzzzzzz最大),修补就是在这个序列上向后移动 步;若移动后越界输出-1,否则输出新的 10 字母串。输入有多组,读到文件结束。把刻印看成 26 进制数
长度为 10、每位取
a~z的串,与区间 内的整数一一对应(a记 0,z记 25)。字典序与数值大小一致,因此“向后移动 步”就是给这个整数加上 。- 编码:
res = res * 26 + (s[i] - 'a'),从高位到低位逐位累加; - 最大合法值:
up = 26^10 - 1,代码中用同样的方式累加'z' - 'a' = 25得到; - 越界判定:
res + K > up时无解,输出-1。
注意 ,而 ,加法结果仍在
long long范围内(),不会溢出,所以可以直接整数比较,不需要先判断 是否过大。解码
得到新值
res后,从最高位 到最低位 依次确定每一位:- 该位权重为 ,这一位的数字就是 ;
- 代码用
while (res >= sum) { res -= sum; j++; }做减法计数,等价于上面的除法取整,并同时把余数留在res中供低位使用; - 因为越界检查保证了 ,所以每一位得到的
j都在 内,加上'a'就是合法字母。
powl(26, i)返回long double再赋给整型。,可以被浮点数精确表示,因此这里不会有精度误差。复杂度
每组数据只需一次 的编码、一次比较和最多 次减法,时间 ,空间 。
代码
#include<bits/stdc++.h> #define int long long #define dd double #define str string #define el cout << '\n' #define re return #define ff first #define ss second #define pll pair<int,int> #define pdd pair<dd,dd> #define all(x) x.begin(),x.end() #define pb push_back using namespace std; str s; int K; void go(){ int res = 0; // 当前刻印对应的 26 进制数值(a=0 ... z=25) int up = 0; // 最大合法值,即 zzzzzzzzzz 对应的数值 26^10 - 1 for(int i=0;i<10;i++){ res = res*26 + s[i]-'a'; up = up*26 + 'z'-'a'; } res += K; // 向后移动 K 步 if(res> up){ // 越界:移动后的刻印不存在 cout<<-1;el;re; } // 按 26 进制从高位到低位还原字符 str ans = ""; for(int i=9;i>=0;i--){ int sum = powl(26, i); // 第 i 位的权重 26^i(在 double 精度内精确) int j = 0; while (res >= sum) // 减法计数,等价于 res / sum 取整 { res -= sum; j++; } ans += (j+'a'); } cout<<ans;el; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int _=1; // 本题为多组数据且不先给出 T,故用 EOF 控制循环,不读组数 while(cin>>s>>K){ go(); } return 0; } - 编码:
- 1
信息
- ID
- 42
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者