这是网络赛的H题,当时看到题的第一个想法就是构造,但是由于各种各样的问题加上构造的代码又太繁琐了,所以当时放下了这个题,没有做出来
后来看题解,网上大部分都是用搜索过的,是用的暴搜+剪枝?还是什么高效的搜索。。。反正我没看懂Orz,后来又往搜索的地方想了一下发现还是没办法控制
时间到一个能接受的范围。。。不确定性太高了,然后就接着自己的构造思想开始写,今天大概写了1个小时。。但是调试用掉了2个小时左右。。没办法。。我太弱了。。。
思路:
枚举答案与输入的数字前面有多少位相同,如果数有10位,那么我们只需要枚举有9~1相同就可以了,因为如果9~1都没构造出一个可行解答案肯定就是9个9了啊
枚举了前面有多少位相同之后把前面的数(包括不相同的第一位)和并成一个数列,然后再枚举这个数列的哪一位是对称的中心位,然后再根据中心位开始填后面的数字,然后找到一个最大的解输出就可以了。
比如输入一个数字
111222334567888 答案应该是111222334554321
现在来说一下构造过程
其实我们处理的是
111222334567887
当我们枚举到答案和数字前10位都相同时:
然后枚举第11位为d[10]-1~0
当枚举到第11位为5时
把前11位合并成一个数列
12345
然后开始枚举对称中心
当枚举到对称中心是5时直接开始填数
因为5比4大所以一直填5直到后面剩余的没填的数的个数等于4时把4321填到最后
如果合并了之后为
12354
4小于5所以先填一个5
然后比较3和5的大小发现5比3大就一直填5直到剩下的个数等于3时把321填到最后
当然还要很多种情况需要考虑比如对称中心不在12345中时等情况
这种情况就直接在末尾填54321然后如果还有没填的空就全部填9
等等。。。其实只要想到先枚举有几位相同然后再枚举对称中心在哪,后面的构造就很容易想到了,复杂度低于18的3次方~~~~
上一个我的巨挫的代码仅供参考。。其实比赛的时候还是应该直接搜的。。。。。
#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<time.h>
#include<set>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
#define inf 0x7fffffff
#define lc l,m,index<<1
#define rc m+1,r,index<<1|1
#define max_n 100005
#define mod 1000000007
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define LL long long
int d[20];
int l;
bool check(LL b)
{
l=0;
while(b)
{
d[l++]=b%10;
b/=10;
}
int d2[20];
int l1=0;
for(int i=0;i<l;i++)
{
if(!l1 || d[i]!=d[i-1])
d2[l1++]=d[i];
}
int L=0,R=l1-1;
while(L<=R)
{
if(d2[L]!=d2[R]) return 0;
L++;
R--;
}
return 1;
}
LL solve(LL n)
{
n--;
if(n<10) return n;
LL b=n;
if(check(b)) return n;
LL res=0;
for(int i=0;i<l;i++)//枚举从哪个数开始不同
{
int a=check(b);
int d2[20];
int l2=0;
LL mind=-1;
int la=d[i]-1;
for(int j=la;j>=0;j--)
{
l2=0;
d[i]=j;
LL ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(check(ans))
{
if(mind<ans)
mind=ans;
}
for(int k=i;k<l;k++)//右侧的数
{
if(!l2) d2[l2++]=j;
else if(d2[l2-1]!=d[k]) d2[l2++]=d[k];
}
for(int id=0;id<=(l2-1)/2;id++)//枚举对称值不包含没有对称情况
{
int L=id,R=id;
bool flag=1;
while(L>=0 && R<l2)
{
if(d2[L]!=d2[R])
{
flag=0;
break;
}
L--;
R++;
}
if(!flag) continue;
if(l2-R>i) continue;
if(R==l2)
{
for(int k=0;k<i;k++)
d[k]=d2[0];
ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(ans>mind) mind=ans;
//continue;
}
if(R==l2-1)
{
if(d2[l2-1]<d2[l2-2])
{
L=i-1;
while(L>0)
{
d[L]=d2[l2-2];
L--;
}
d[0]=d2[l2-1];
}
else
{
for(int k=0;k<i;k++)
d[k]=d2[0];
}
ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(ans>mind) mind=ans;
//continue;
}
L=i-1;
int r=R;
R--;
while(L>=0 && R<l2)
{
if(d2[R]>d2[R+1] || R==l2)
{
while(L>=l2-R-1)
{
d[L]=d2[R];
L--;
}
R++;
while(L>=0)
{
d[L]=d2[R];
L--;
R++;
}
}
else
d[L--]=d2[R++];
}
ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(ans>mind) mind=ans;
R=r;
L=i-1;
//R--;
while(L>=0 && R<l2)
{
if(d2[R]>d2[R+1] || R+1==l2)
{
while(L>=l2-R-1)
{
d[L]=d2[R];
L--;
}
R++;
while(L>=0)
{
d[L]=d2[R];
L--;
R++;
}
}
else
d[L--]=d2[R++];
}
ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(ans>mind) mind=ans;
}
if(i<l2) continue;
//不含对称值的情况
for(int k=0;k<i;k++)
{
if(l2>0)
d[k]=d2[l2-1];
else
d[k]=9;
l2--;
}
ans=0;
for(int k=l-1;k>=0;k--)
ans=ans*10+d[k];
if(ans>mind) mind=ans;
}
if(mind>0) return mind;
}
check(b);
for(int i=0;i<l-1;i++)
res=res*10+9;
return res;
}
//LL a[10000000];
int main()
{
LL T;
//freopen("C:\\Users\\admin\\Desktop\\out.txt","r",stdin);
//freopen("C:\\Users\\admin\\Desktop\\output.txt","w",stdout);
LL i,n;
scanf("%lld",&T);
i=1;
/* while(~scanf("%lld",&a[i]))
{
// printf("%lld\n",a[i]);
i++;
}*/
// for(n=1;n<=1000000;n++)
while(T--)
{
scanf("%lld",&n);
printf("%lld\n",solve(n));
/*if(a[n]!=solve(n))
{
printf("%lld %lld %lld\n",n,a[n],solve(n));
//system("pause");
}*/
}
return 0;
}