k叉哈夫曼树,平衡整颗树即可
然后开个双队列由小到大做
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #define LL long long #define fo(i,a,b) for(int i=a;i<=b;i++) #define efo(i,x) for(int i=last[x];i!=0;i=e[i].next) using namespace std; inline LL read() { LL d=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s-getchar();} while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();} return d*f; } #define N 100005 LL a[N],w[N]; int n,m; struct edge { LL num,dep; }sta1[N],sta2[N]; LL h1=1,h2=1,t1,t2=0; edge get() { if(h2>t2)return sta1[h1++]; if(h1>t1)return sta2[h2++]; if(sta1[h1].num==sta2[h2].num) { if(sta1[h1].dep<sta2[h2].dep)return sta1[h1++]; else return sta2[h2++]; } if(sta1[h1].num<sta2[h2].num)return sta1[h1++]; else return sta2[h2++]; } void add(LL x,int de) { sta2[++t2].num=x; sta2[t2].dep=de; } void check() { cout<<"New:\n"; cout<<h1<<' '<<t1<<' '<<h2<<' '<<t2<<endl; cout<<"stack1.num:"; fo(i,h1,t1)cout<<sta1[i].num<<' ';cout<<endl; cout<<"stack1.dep:"; fo(i,h1,t1)cout<<sta1[i].dep<<' ';cout<<endl; cout<<"stack2.num:"; fo(i,h2,t2)cout<<sta2[i].num<<' ';cout<<endl; cout<<"stack2.dep:"; fo(i,h2,t2)cout<<sta2[i].dep<<' ';cout<<endl; } int main() { memset(w,0,sizeof(w)); n=read();m=read(); fo(i,1,n)w[i]=read(); while((n-1)%(m-1)!=0)n++; sort(w+1,w+n+1); fo(i,1,n) { sta1[i].num=w[i]; sta1[i].dep=0; } int cnt=n,dep=1;t1=n; LL ans=0; while(cnt!=1) { LL ret=0,len=0; fo(i,1,m) { edge t=get(); ret+=t.num,cnt--; len=max(len,t.dep); } ans+=ret; add(ret,len+1);cnt++; // check(); } cout<<ans<<endl<<sta2[h2].dep<<endl; return 0; }