这题好神-_-
我们考虑对序列里的每一个数a[i],求一个集合s[i],代表a[i]中必须出现的数字集合
初始的时候每个s[i]里都只有输入的那个数
我们另x[i]=a[i]/10(整除)y[i]=a[i]%10(即a[i]的个位)
然后我们枚举第一个数的个位,即y[1],y[1]确定后所有的y就都确定了,然后如果s[i]中包含了y[i],那么就可以从s[i]中删掉y[i]
我们知道数列a是连续的,所以相邻的一些x[i]是相等的,并且根据y[i]的变化情况我们可以知道哪些x是相等的,那么我们把x相等的s都合并起来,这样就得到了长度大概为n/10的新序列a',a'依旧是连续的,并且我们也知道新的s,所以就可以递归处理了,当n=1的时候就是递归出口,可以根据哪些数必须出现贪心第算最小值,这样复杂度就是O(n log n)的
实现的时候有一些细节要注意,主要是一下几点:
当n=1时,如果前面已经枚举好的位都是0,那么返回值不能是0
n=1时,可以返回零,但不能出前导零
如果在一层递归中,有一个s[i]中包含零,并且y[i]==0,那么这层递归的返回值不能为0
开long long
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 100010
#define MAXM 10000010
#define INF 1000000000000000000ll
#define MOD 1000000007
#define eps 1e-8
#define ll long long
int n;
int memp[MAXM];
ll cal(int *a,int n,bool flag,bool flag2){
ll i,j;
ll re=INF;
if(n==1){
if(!a[1]&&!flag){
return 1;
}
bool flag=0;
re=0;
for(i=1;i<=9;i++){
if(a[1]&(1<<i)){
flag=1;
re=i;
a[1]^=(1<<i);
break;
}
}
if(!flag&&(a[1]&1)){
re=1;
}
for(i=0;i<=9;i++){
if(a[1]&(1<<i)){
re*=10;
re+=i;
}
}
return re;
}
for(i=0;i<=9;i++){
if(i==9&&!flag2){
break;
}
int now=i;
int N=1;
int *r=a+n;
r[1]=0;
bool f=0;
for(j=1;j<=n;j++){
r[N]|=a[j]^(a[j]&(1<<now));
if(!now&&(a[j]&1)){
f=1;
}
if(j!=n&&++now==10){
r[++N]=0;
now=0;
}
}
ll t=cal(a+n,N,flag||i,i!=9||n>2)*10+i;
if(!t&&f){
t=10;
}
re=min(re,t);
}
return re;
}
int main(){
ll i,x;
scanf("%lld",&n);
for(i=1;i<=n;i++){
scanf("%lld",&x);
memp[i]=1<<x;
}
printf("%lld\n",cal(memp,n,0,1));
return 0;
}
/*
*/