「杂题乱刷2」at_abc363_d

题目链接

abc363d

解题思路

比较无脑的思路。

你考虑到,你只需要确定前半部分的数字也就可以构造出后面的部分使此数字回文。

于是可以进行数位 dp 来进行计数 \(1 \sim n\) 中有几个回文数,再二分答案即可。

状态大概是 \(dp_{x,0/1}\) 表示考虑到前 \(x\) 为目前的数字大小有无填满的方案数。

时间复杂度 \(O(\log V \log^2 n)\),其中 \(V\) 为答案值域,这里我取了 \(10^{36}\)

由于计数的是 \(1 \sim n\),所以记得将 \(n\) 减去 \(1\) 再计算。

注意特判 \(n = 1\) 的情况。

参考代码

点击查看代码
/*
Tips:
你数组开小了吗?
你MLE了吗?
你觉得是贪心,是不是该想想dp?
一个小时没调出来,是不是该考虑换题?
*/
#include<bits/stdc++.h>
using namespace std;
#define map unordered_map
#define forl(i,a,b) for(register long long i=a;i<=b;i++)
#define forr(i,a,b) for(register long long i=a;i>=b;i--)
#define lc(x) x<<1
#define rc(x) x<<1|1
#define mid (l+r)>>1
#define cin(x) scanf("%lld",&x)
#define cout(x) printf("%lld",x)
#define lowbit(x) x&-x
#define pb push_back
#define pf push_front
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
#define ll __int128
int t;
string s;
ll a[110],dp[110][2],k,b[110],len,mod=9e18;
void cl()
{
	forl(i,0,108)
		forl(j,0,1)
			a[i]=0,dp[i][j]=-1,b[i]=0;
	len=0;k=0;
}
bool check()
{
	for(int i=k,j=len/2+len%2;i&&j;i--,j--)
		if(b[i]!=a[j])
			return b[i]<a[j];
	return 1;
}
string f(__int128 x)
{
	string s="";
	while(x)
		s+=x%10+'0',x/=10;
	reverse(s.begin(),s.end());
	return s;
}
__int128 Mid;
__int128 L=1,R=1e36;
ll dfs(ll last,bool _1)
{
	if(last==len/2)
	{
		if(_1==0)
			return 1;
		else
			return check();
	}
	if(dp[last][_1]>=0)
		return dp[last][_1];
	ll maxn=_1?a[last]:9,ans=0;
	forl(i,0,maxn)
	{
		if(last==len && i==0)
			continue;
		b[++k]=i;
		ans+=dfs(last-1,_1&&i==maxn)%mod;ans%=mod;
		k--;
	}
	return dp[last][_1]=ans;
}
ll sol(string s)
{
//	cin>>s;
	len=s.size();
	forl(i,0,len-1)
		a[len-i]=s[i]-'0';
	ll ans=0;
	forr(i,len-1,1)
	{
		ll sum=9;
		forr(j,i-1,i/2+1)
			sum*=10,sum%=mod;
		ans+=sum%mod,ans%=mod;
	}
	forl(i,0,105)
		dp[i][0]=dp[i][1]=-1;
	ans+=dfs(len,1)%mod;
	return ans%mod;
}
long long n;
void print(__int128 x)
{
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

void solve()
{
	cin>>n;
	n--;
	if(n==0)
	{
		cout<<0<<endl;
		return ;
	}
	while(L<R)
	{
		cl();
		Mid=(L+R)/2;
		if(sol(f(Mid))<n)
			L=Mid+1;
		else
			R=Mid;//,cout<<"!";
	}
	//L--;
//	print(sol(f(L)));
//	cout<<endl;
	print(L);
}
/*
1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
*/
int main()
{
//	IOS;
	t=1;
//	cin>>t;
	while(t--)
		solve();
    /******************/
	/*while(L<q[i].l) */
	/*    del(a[L++]);*/
	/*while(L>q[i].l) */
	/*    add(a[--L]);*/
	/*while(R<q[i].r) */
	/*	  add(a[++R]);*/
	/*while(R>q[i].r) */
	/*    del(a[R--]);*/
    /******************/
	QwQ;
}
posted @ 2024-07-21 01:04  wangmarui  阅读(13)  评论(0编辑  收藏  举报