翻译
定义一个数为美丽数,当且仅当这个数长度为偶数,且他的某一个排列可以组成一个回文数
给出n(n<=2*10^100000),求小于n的最大美丽数
题解
从定义中可以发现,一个数为美丽数的情况,当且仅当他出现过的所有数字出现的次数均为偶数次
贪心地想,如果这个数较高的位能取大,那么一定取大
预处理在当前位置i,每个数字出现的次数是偶数次还是奇数次
枚举一个位置i,表示第i位更改,1~i-1位不变
枚举这个位置改成数j
然后可以处理出在i,现在每个数字出现的次数是奇数还是偶数次
设cnt表示在i出现次数为奇数次的数
如果len-i < cnt,表示后面没有那么多位置可以把前面需要补成偶数次的数补成偶数次,那么继续枚举
否则,i+1~len-cnt位全部填9,len-cnt+1~len位从高到低填需要补偶的数
如果找不到,那么直接输出len-2个9
特判两种情况
对于len为奇数,直接输出len-1个9
对于首位为1,末尾为0或1,其他位为0的情况,直接输出len-2个9
/*
翻译:
定义一个数为美丽数,当且仅当这个数长度为偶数,且他的某一个排列可以组成一个回文数
给出n(n<=2*10^100000),求小于n的最大美丽数
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
char ch[210000];
int a[210000],g[15],len;
int f[210000][10];
void sol()
{
for(int i=len;i>=1;i--)
for(int j=a[i]-1;j>=0;j--)
{
if(i==1 && j==0)break;
int cnt=0,maxx=0;
for(int k=0;k<=9;k++)
{
int op=0;if(k==j)op=1;
if(f[i-1][k]^op==1)cnt++,maxx=k;
}
if(len-i<cnt)continue;
for(int k=1;k<=i-1;k++)printf("%d",a[k]);
printf("%d",j);
for(int k=i+1;k<=len-cnt;k++)printf("9");
int t=maxx;
for(int k=len-cnt+1;k<=len;k++)
{
int op=0;if(t==j)op=1;else op=0;
while(f[i-1][t]^op!=1){t--;if(t==j)op=1;else op=0;}
printf("%d",t);t--;
}
printf("\n");
return ;
}
for(int i=1;i<len-2;i++)printf("9");
printf("\n");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(g,0,sizeof(g));
scanf("%s",ch+1);len=strlen(ch+1);
for(int i=1;i<=len;i++)a[i]=ch[i]-'0',g[a[i]]++;
if(len%2==1)
{
for(int i=1;i<len;i++)printf("9");
printf("\n");continue;
}
if((g[1]==1 && g[0]==len-1 && a[1]==1) || (g[1]==2 && g[0]==len-2 && a[1]==1 && a[len]==1))
{
for(int i=1;i<len-1;i++)printf("9");
printf("\n");continue;
}
for(int i=0;i<=9;i++)f[0][i]=0;//0 偶数次
for(int i=1;i<=len;i++)
for(int j=0;j<=9;j++)
{
if(a[i]==j)f[i][j]=f[i-1][j]^1;
else f[i][j]=f[i-1][j];
}
sol();
}
return 0;
}