「雜題亂刷2」at_abc363_d

wangmarui發表於2024-07-21

題目連結

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;
}