版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Lfhase/article/details/79488859
题目链接:点击打开链接
题意:定义一种数,这里不妨称之为BN:它的十进制表示只有偶数位数,且不含前导零;此外,它的十进制表示的每个位上的数经过重新排列后能形成回文序列。在这里给定某个数n(十进制下长度不超过2*1e5),求小于它的最大BN。(题目数据保证有解且n不含前导零)
思路:贪心。首先,n的长度可能很大,这里需要使用字符串来处理该数。
因为要找一个比n小的BN数,假设该数的前i位数已经确定,那么第i+1位数的确定即判断是否存在一个满足条件的后缀,而要形成回文序列的性质使得这个后缀数非常好找。寻找的过程即根据已经确定的数,找到出现次数为奇数的所有数,从小到大排到后缀的最后即可,中间部分(贪心地)用0补充。
这里因为前缀必然是满足条件的,所以随着i的增大,寻找后缀的方法不变:即判断第i+1位数是否存在一个满足条件的后缀,如果满足那么就判断下一位直到最后,否则令现有的i+1位前缀减1,继续执行上述判断。 所以这样的方式并不具有后效性。故令i从1到len(n)走一遍即可,若直到出现前导零时都找不到解,那么需要将位数减小,新位数下所有数必然小于n,故全为9。
AC代码如下:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
const int MAXN = 2000005;
int cnt[10];
string ss;
string tt;
int flag;
vector<int> comp;
int check(int pos)
{
comp.clear();
int allzero = 1;
tt[pos-1] = ss[pos-1];
cnt[ss[pos-1]-'0']++;
for(int i=0; i<10; ++i)
{
if(cnt[i]%2)
comp.push_back(i);
if(cnt[i]&&i) allzero=0;
}
if(allzero) return 0;
sort(comp.begin(),comp.end());
int len = comp.size();
if(len==0) return 1;
if(comp.size()<ss.length()-pos) return 1;
if(comp.size()>ss.length()-pos) return 0;
for(int i=1; i<=len; ++i)
tt[ss.length()-i] = '0'+comp[len-i];
/*
string ttmp = ss;
string ssmp = tt;*/
for(int i=pos; i<ss.length(); ++i)
{
if(tt[i]<ss[i]) return 1;
else if(tt[i]>ss[i]) return 0;
}
return 1;
}
int reduce(int pos)
{
for(int i=pos+1; i<ss.length(); ++i) ss[i]='9',tt[i]='0';
int tmp = pos;
while(tmp>=0&&ss[tmp]=='0')
{
ss[tmp]='9';
tt[tmp]='0';
cnt[0]--;
tmp--;
}
if(tmp<0) return -1;
cnt[ss[tmp]-'0']--;
ss[tmp]--;
if(ss[0]=='0') return -1;
return tmp;
}
void solve()
{
memset(cnt,0,sizeof(cnt));
for(int j=0; j<ss.length(); ++j) cnt[ss[j]-'0']++;
int isbeautiful = 1;
for(int j=0; j<10; ++j)
{
if(cnt[j]%2)
{
isbeautiful=0;
break;
}
}
if(isbeautiful) reduce(ss.length()-1);
memset(cnt,0,sizeof(cnt));
tt = string(ss.length(),'0');
for(int i=0; i<ss.length(); ++i)
{
if(!check(i+1))
{
int retmp = reduce(i);
if(retmp==-1)
{
for(int j=1; j<=ss.length()-2; ++j)
cout<<'9';
cout<<endl;
return;
}
i = retmp - 1;
//cout<<ss<<endl;
}
}
cout<<tt<<endl;
}
int main()
{
FSIO;
int T;
cin>>T;
while(T--)
{
flag = 0;
cin>>ss;
solve();
}
return 0;
}