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 Format
输入的第1行为一个正整数n,为集合S初始元素个数。
第2行包含n个正整数a1,a2, ..., an,数之间空格隔开,为S中初始元素。
Output Format
输出包括一个正整数,为最小代价。
思路:如果a能生成b,那么b也可以生成a,首先我们从n个数里面bfs去生成其他数字,将代价建为边,由于要求最小的生成所有数的代价,因此很容易想到最小生成树,建一个0节点,对初始n个数字建边,边权为0,做最小生成树即可。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 struct edge{ 8 int u,v,w; 9 }e[200005]; 10 int vis[1000005],c[1000005],b[1000005],n,tot,fa[200005],mx,h,t; 11 bool cmp(edge a,edge b){ 12 return a.w<b.w; 13 } 14 int find(int x){ 15 if (fa[x]==x) return x; 16 else return (fa[x]=find(fa[x])); 17 } 18 void MST(){ 19 for (int i=1;i<=n;i++){ 20 e[++tot].u=0; 21 e[++tot].v=c[i]; 22 e[++tot].w=0; 23 } 24 std::sort(e+1,e+1+tot,cmp); 25 for (int i=0;i<=100000;i++) fa[i]=i; 26 ll ans=0; 27 for (int i=1;i<=tot;i++){ 28 int p=find(e[i].u),q=find(e[i].v); 29 if (p==q) continue; 30 fa[p]=q; 31 ans+=(ll)e[i].w; 32 } 33 printf("%lld\n",ans); 34 } 35 int query(int x){ 36 int cnt=0; 37 while (x){ 38 x/=10;cnt++; 39 } 40 return cnt; 41 } 42 void work(int x){ 43 int T=0,Len=0,y=x; 44 while (y){ 45 b[Len++]=y%10; 46 y/=10; 47 } 48 49 for (int i=0;i<Len;i++) 50 for (int j=i+1;j<Len;j++){ 51 std::swap(b[i],b[j]); 52 int cost=((b[i]&b[j])+(b[i]^b[j]))*2; 53 T=0; 54 for (int k=Len-1;k>=0;k--) 55 T=T*10+b[k]; 56 if (T==x||query(T)>mx) continue; 57 if (!vis[T]) vis[T]=1,c[++t]=T; 58 e[++tot].u=x;e[tot].v=T;e[tot].w=cost; 59 std::swap(b[i],b[j]); 60 } 61 if (Len>2){ 62 for (int i=0;i<Len;i++){ 63 int L=b[(i+1)%Len],R=b[(i-1+Len)%Len]; 64 if (b[i]<L||b[i]>R) continue; 65 int cost=b[i]+(L^R)+(L&R); 66 T=0; 67 for (int j=Len-1;j>=0;j--) 68 if (j!=i) 69 T=T*10+b[j]; 70 if (query(T)>mx) continue; 71 e[++tot].u=x,e[tot].v=T,e[tot].w=cost; 72 if (!vis[T]) vis[T]=1,c[++t]=T; 73 } 74 }else 75 if (Len==2){ 76 if (b[0]==b[1]){ 77 T=b[0]; 78 if (query(T)<=mx){ 79 if (!vis[T]) vis[T]=1,c[++t]=T; 80 int cost=b[0]+(b[0]^b[1])+(b[0]&b[1]); 81 e[++tot].u=x;e[tot].v=T;e[tot].w=cost; 82 } 83 } 84 } 85 for (int i=0;i<Len;i++){ 86 int L=b[(i+1)%Len],R=b[(i+Len)%Len]; 87 for (int j=L;j<=R;j++){ 88 T=0; 89 for (int k=Len-1;k>=0;k--) 90 if (k==i) 91 T=T*10+j,T=T*10+b[k]; 92 else 93 T=T*10+b[k]; 94 if (query(T)>mx) break; 95 if (!vis[T]) vis[T]=1,c[++t]=T; 96 int cost=T+(L^R)+(L&R); 97 e[++tot].u=x;e[tot].v=T;e[tot].w=cost; 98 } 99 } 100 int L=b[0],R=b[Len-1]; 101 for (int j=L;j<=R;j++){ 102 T=0; 103 for (int k=Len-1;k>=0;k--) 104 T=T*10+b[k]; 105 T=T*10+j; 106 if (query(T)>mx) break; 107 if (!vis[T]) vis[T]=1,c[++t]=T; 108 int cost=T+(L^R)+(L&R); 109 e[++tot].u=x;e[tot].v=T;e[tot].w=cost; 110 } 111 } 112 int main(){ 113 scanf("%d",&n); 114 for (int i=1;i<=n;i++){ 115 scanf("%d",&c[i]); 116 int T=c[i],cnt=0; 117 while (T){ 118 cnt++;T/=10; 119 } 120 mx=std::max(mx,cnt); 121 vis[c[i]]=1; 122 } 123 h=1,t=n; 124 while (h<=t){ 125 int now=c[h++]; 126 work(now); 127 } 128 for (int i=1;i<=t;i++) 129 printf("%d\n",c[i]); 130 MST(); 131 }