Description
一个数x可以按以下规则生成数字:
1、将任意两位交换,若交换的数字为a和b,生成的代价为((a and b)+(a xor b))*2。
例如134可以生成431,因为431可以从134的个位(4)与百位(1)交换后得到,代价为((1 and 4)+(1 xor 4))*2=10。
2、将其中一位数删除,但是删除的数要满足大于等于它左边的数,且小等于它右边的数,并且定义最高位左边的数为个位,个位右边的数为最高位。若删除的数字为a,它左边的数为b,它右边的数为c,则生成的代价为a+(b and c)+(b xor c)。
例如212,可以删除个位的数得到21,但是因为2>1,所以1是不能被删除的。特别地,若x为两位数,它能删除当且仅当x的两位数相同,若x为一位数,它是不能被删除的。
3、在两位数字之间,也可以是数字的前面或后面加入一位数,同样地,加入的数要满足大等于它左边的数,且小等于它右边的数,并且定义最高位左边的数为个位,个位右边的数为最高位。若加入的数字为a,它左边的数为b,它右边的数为c,则生成的代价为a+(b and c)+(b xor c)。
例如241,它可以在2与4之间加入一个3,生成2341,也可以在数的末尾加入一个1或者2,当然还有其它可以生成的数,但是不能在4和1之间加入数字。
你的任务是,S一开始为n个不同的给定数组成的集合,每次可以从S中取出一个数生成一个满足生成规则的数加入S中,并且取出的数仍然存在于S中。生成的数的位数不能大于S初始集合最大的数的位数。问在S元素最多的情况下,总代价最小是多少。
Input
输入的第1行为一个正整数n,为集合S初始元素个数。
第2行包含n个正整数a1,a2, …, an,数之间空格隔开,为S中初始元素。
Output
输出包括一个正整数,为最小代价。
Sample Input
2
111 22
Sample Output
12
Data Constraint
Hint
【样例说明】
111删除1得到11,代价为2,11删除1得到1,代价为2,同样22删除和加入一个2得到2,222,代价均为4,总代价2+2+4+4=12。111无法生成1111因为111为一个3位数,而1111为一个4位数。
利用交换/添加规则无法让集合元素更多,所以最小代价为12。
【数据规模】
对于20%的数据,有ai<100;
对于40%的数据,有ai<1000;
对于50%的数据,有n=1;
对于60%的数据,有ai<10000;
对于100%的数据,有ai<100000,n≤5,保证的任何一位不包含0。
思路
对于一开始只有一个数字的情况,如果A能生成B那么A向B连一条边,由于所有生成规则都是可逆的,且代价相同,所以连出的是无向边。BFS出所有能生成的数字,并构图,最后即变成了最小生成树的模型,一开始的数为最小生成树的根,生成树上的边为生成数字的过程。由于图比较稀疏,所以用Kruskal就可以。
对于多个数字的情况,只要一开始在这些数字之间连条权为0的边即可。范围较小,并且图比较一般,不一定要加什么优化。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[6],bz[100010],r[100010],cnt=0,maxp=1,s=0;
struct E
{
int x,y,l;
}e[500010];
bool cmp(E x,E y)
{
return x.x<y.x;
}
void add(int x,int y,int l)
{
e[++cnt].x=x,e[cnt].y=y,e[cnt].l=l;
}
void dfs(int x)
{
int t=x,t1=0,l=0,c[6],d[6];
while(t>0) c[++l]=t%10,t/=10;
for(int i=1; i<l; i++)
for(int j=i+1; j<=l; j++)
{
for(int k=1; k<=l; k++) d[k]=c[k];
d[i]=c[j],d[j]=c[i];
t=0;
for(int k=l; k>0; k--) t=t*10+d[k];
if(t==x) continue;
add(x,t,(c[i]&c[j])*2+(c[i]^c[j])*2);
if(!bz[t]) bz[t]=1,s++,dfs(t);
}
if(l>1)
{
for(int i=1; i<=l; i++)
{
int p=i+1,q=i-1;
if(p>l) p=1;
if(q<1) q=l;
if(c[i]>=c[p]&&c[i]<=c[q])
{
t=0;
for(int j=l; j>0; j--) if(j!=i) t=t*10+c[j];
add(x,t,c[i]+(c[p]&c[q])+(c[p]^c[q]));
if(!bz[t]) bz[t]=true,s++,dfs(t);
}
}
}
if(x*10>=maxp) return;
for(int i=c[1]; i<=c[l]; i++)
{
t=x*10+i;
add(x,t,i+(c[1]&c[l])+(c[1]^c[l]));
if(!bz[t]) bz[t]=1,s++,dfs(t);
t=i;
for(int j=l; j>0; j--) t=t*10+c[j];
add(x,t,i+(c[1]&c[l])+(c[1]^c[l]));
if(!bz[t]) bz[t]=1,s++,dfs(t);
}
for(int i=1; i<l; i++)
for(int j=c[i+1]; j<=c[i]; j++)
{
t=0;
for(int k=l; k>0; k--) if(k==i) t=(t*10+j)*10+c[k]; else t=t*10+c[k];
add(x,t,j+(c[i+1]&c[i])+(c[i+1]^c[i]));
if(!bz[t]) bz[t]=1,s++,dfs(t);
}
}
int get(int k)
{
if(r[k]==k) return k;
else
{
r[k]=get(r[k]);
return r[k];
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
bz[a[i]]=1; s++;
for(int j=1; j<i; j++) add(a[i],a[j],0);
while(a[i]>=maxp) maxp*=10;
}
for(int i=1; i<=n; i++) dfs(a[i]);
for(int i=1; i<maxp; i++) r[i]=i;
int i=1,ans=0;
sort(e+1,e+cnt+1,cmp);
while(s>1)
{
int p=get(e[i].x),q=get(e[i].y);
if(p!=q)
{
ans+=e[i].l;
r[p]=q;
s--;
}
i++;
}
printf("%d",ans);
return 0;
}