T1 题解-最近回文数

T1 题解-最近回文数


题目:

题目背景

小X最近闲来无事,开始切水题。
他看到 最近回文数 这道题,轻松打了一个数位dp。
然而他觉得数位dp有点小题大做了,想了想,用一个简单的算法,瞬间AC。
他觉得非常有趣,边来考考大家。(小X不是我,他的出处是 P2107 小Z的AK计划

题目描述

输入一个整数,找到与它的差的绝对值最小的回文数。当有两个解时,取较小的那一个解。

输入格式

输入为一行,包括一个整数 n n n

输出格式

输出只有一个整数,为与输入数字的差的绝对值最小的回文数。

样例输入

10000

样例输出

9999

数据范围

对于 20 % 20\% 20% 的数据, n ≤ 1 0 20 n \leq 10^{20} n1020
对于 60 % 60\% 60% 的数据, n ≤ 1 0 100 n \leq 10^{100} n10100
对于 100 % 100\% 100% 的数据, n ≤ 1 0 10000 n \leq 10^{10000} n1010000

乍看似乎不难:

算法(简单)

枚举差的绝对值,逐个判断是否是回文数,直到找到回文数为止。

仔细审题发现 n n n 的长度至多为 1000 1000 1000位,而 long long 也才约 1 0 20 10^{20} 1020

可以用字符串模拟大整数。

写出代码:

#include <iostream>
#include <string>
using namespace std;
 
 
string plus_one(string n) {
    string back = n;
    int last_number = (int)n[n.size() - 1] - '0';
    if (last_number < 9) {
        back[back.size() - 1] = (char)((int)back[back.size() - 1] + 1);
    } else {
        int i = n.size() - 1;
        while (last_number == 9 && i > 0) {
            back[i] = '0';
            i--;            
			last_number = back[i] - '0';
        }
		
        if (last_number != 9) {
            back[i] = (char)((int)back[i] + 1);
        } else {
            back[0] = '1';
            back = back + '0';
        }
    } 
 
    return back;
}
 
 
string minus_one(string n) {
    string back = n;
    int last_number = (int)n[n.size() - 1] - '0';
    if (last_number > 0) {
        back[back.size() - 1] = (char)((int)back[back.size() - 1] - 1);
    } else {
        int i = n.size() - 1;
        while (last_number == 0 && i > 0) {
            back[i] = '9';
            i--;            
			last_number = back[i] - '0';
        }
		
        if (last_number != 1) {
            back[i] = (char)((int)back[i] - 1);
        } 
    }

    return back;
}
 
 
bool repet(string n) {
    string backn;
	
	for (int i = 0; i < n.size()/2; i++) {
        if (n[i] != n[n.size() - i - 1]){
			return false;
		}
    }
    return true;
}
 
 
int main() {
    string n;
    cin >> n;
 
 
	string plus_n = n;
	string minus_n = n;
	
	if (repet(n)){
		    cout << n << endl;
			return 0;
	}
		
	while(minus_n.size() > 1){
	    minus_n = minus_one(minus_n);
	    if (true == repet(minus_n)){
		    cout << minus_n << endl;
			break;
	    }
 
 
	    plus_n = plus_one(plus_n);
	    if (true == repet(plus_n)){
		    cout << plus_n << endl;
			break;
	    }
	}
		
    return 0;
}

不要忘了时间限制(1000ms),对于超过 1 0 100 10^{100} 10100的数会非常慢。

我们需要一个效率高的算法:

算法(最终)

一位一位判断:

条件Condition

A1-如果高位小于低位且低位减高位小于等于5
A2-如果高位小于低位且低位减高位大于5
B1-如果高位不小于低位且高位减低位小于5
B2-如果高位不小于低位且高位减低位不小于5

做法Action

A1:低位赋值为高位 e.g. 155->151
A2:低位赋值为高位,低+1位+1 e.g. 159->161
B1:低位赋值为高位 e.g. 451->454
B2:低位赋值为高位,低+1位-1 e.g. 751->747

最终代码:

#include <iostream>
#include <string>
using namespace std;
 
string write_c(int t, char a) {
    string back = "";
    for (int i = 0; i < t; i++) {
        back += a;
    }
    return back;
}
 
string plus_one(string n) {
    string back = n;
    int last_number = (int)n[n.size() - 1] - '0';
    if (last_number < 9) {
        back[back.size() - 1] = (char)((int)back[back.size() - 1] + 1);
    } else {
        int i = n.size() - 1;
        while (last_number == 9 && i > 0) {
            back[i] = '0';
            i--;            
			last_number = back[i] - '0';
        }
		
        if (last_number != 9) {
            back[i] = (char)((int)back[i] + 1);
        } else {
            back[0] = '1';
            back = back + '0';
        }
    }
    return back;
}
 
string sub_one(string n) {
    string back = n;
    int last_number = (int)n[n.size() - 1] - '0';
    if (last_number > 0) {
        back[back.size() - 1] = (char)((int)back[back.size() - 1] - 1);
    } else {
        int i = n.size() - 1;
        while (last_number == 0 && i > 0) {
            back[i] = '9';
            i--;            
			last_number = back[i] - '0';
        }
		
        if (last_number != 1) {
            back[i] = (char)((int)back[i] - 1);
        } 
    }
	return back;
}
 
bool one_with_zero(string s) {
    if (s[0] != '1') {return false;}
    if (s == "1") {return false;}
    for (int i = 1; i < s.size(); i++) {
        if (s[i] != '0') {
            return false;
        }
    }
    return true;
}
 
string A1(string n, int high, int low) {
	n[low] = n[high];
    return n;
}
 
string A2(string n, int high, int low) {
	n = A1(n, high, low);
	string need_plus = n.substr(0, low);
	string other = n.substr(low);
	need_plus = plus_one(need_plus);
	n = need_plus + other;
    return n;
}
 
string B1(string n, int high, int low) {
    n[low] = n[high];
    return n;
}
 
string B2(string n, int high, int low) {
	n = A1(n, high, low);
	string need_sub = n.substr(0, low);
	string other = n.substr(low);
	need_sub = sub_one(need_sub);
	n = need_sub + other;
    return n;
}
 
 
int main() {
    string n;
	cin >> n;
	string ans = n;
	int high = 0, low = n.size() - 1;
    
    if (one_with_zero(n)) {
        ans = write_c(n.size() - 1, '9');
        cout << ans << endl;
        return 0;
    } 
    
	while ((low - high) >= 1) {
        
		if (ans[high] == ans[low]) {
			high++;
			low--;
            continue;
		}
        
        if (ans[high] < ans[low]) { // enter A
			if ((ans[low] - ans[high]) <= 5) {
				ans = A1(ans, high, low);
			} else {
				ans = A2(ans, high, low);
			}
		} else { // enter B
			if ((ans[high] - ans[low]) < 5) {
				ans = B1(ans, high, low);
			} else {
				ans = B2(ans, high, low);
			}
		}
	}
	cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值