ABC363:D - Palindromic Number(回文,构造)

问题陈述

如果一个非负整数 𝑋X 的十进制表示(不含前导零)是一个回文数,那么这个非负整数 𝑋X 就叫做回文数。
例如, 363363 、 1234432112344321 和 00 都是回文数。

求 𝑁N /th最小的回文数。

限制因素
  • 1≤𝑁≤10181≤N≤1018
  • 𝑁N 是整数。
做法

我们构造回文串,只需要知道前半段的回文串长啥样,就可以构造出一整个回文串。

再看看回文串的长度,长度为1时,有10种构造方式(0到9);长度为2时,有9种构造方式(只考虑回文串的前半段,且没有前导0);长度为3时,构造回文串的前两个位,第一位有九种选择(1到9),第二位有10种(0到9)…… 长度为6时,构造前三位,第一位有九种选择,第二位有十种选择,第三位有十种选择。

我们发现,若一个cnt位的回文串,我们需要构造出前(cnt+1)/ 2 位,共有9*10^((cnt+1)/2-1) 种不同的回文串(第一位是9种选择,其他位都是10种选择)。这样我们就能知道第n小的回文数是有几位数构成的了。

那么我们知道了他是几位数构成的,我们又怎么构造出这个回文串呢?我们假设第n大的回文数是由cnt位数字构成的,k是他的前半段的位数,即(cnt+1)/ 2 。那么在cnt位的回文数中,前半段回文数是1*10^(k-1) 的是第一小的回文数,1*10^(k-1)+1是第二小的回文数……这个就是可以用1*10^(k-1)+n-1推出来(n在前面处理时,已经减去了前面1到cnt-1位回文数的个数)。

#include<bits/stdc++.h>
using namespace std;
long long n;
long long ksm(long long a,long long b){
	long long ans=1;
	while(b){
		if(b%2) ans*=a;
		b/=2;
		a*=a;
	}
	return ans;
}
int main() {
	scanf("%lld",&n);
	if(n==1){
		cout<<0;
		return 0;
	}
	n--;
	
	long long cnt=1;//位数
	long long k=(cnt+1)/2;//前面一半
	long  long res=9*ksm(10,k-1);//位数对应的回文串个数 
	
	while(n>res){//找出第n小的回文数的位数
		n-=res;
		cnt++;
		k=(cnt+1)/2;
		res=9*ksm(10,k-1);
	}
	
	long long ans=ksm(10,k-1)+n-1;//求出前半段
	string a=to_string(ans);

	string b=a;
	if(cnt%2==0){//回文串位数为偶数
		reverse(a.begin(),a.end());
		b+=a;
	}

	else{//回文串位数为奇数
		string c=a.substr(0,a.size()-1);
		reverse(c.begin(),c.end());
		b+=c;
	}

	cout<<b;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值