lg9483 [NOI2023] 合并书本
考虑对合并过程建一棵树。
对于一个点
定义一个点的层级
那么层级为
考虑这样一个过程:从浅往深(从大往小)扫每一层
考虑从
然后我们发现两个性质。一个是
于是可以考虑搜索,每次暴力枚举
然后我们发现,对于
int lim;
int t,_,n[15],m,i,j,k,a[15][105],vis[500005],lst[500005];
i64 ans,dis[500005];
int ch[500005][105],cnt;
vector<int> seq[500005];
vector<int> f[105];
int qid(vector<int> v)
{
int x=0,i,len=0;
vector<int> cur;
ff(v,it){
cur.push_back(*it);
if(!ch[x][*it]){
ch[x][*it]=++cnt;
f[cur.size()].push_back(cnt);
seq[cnt]=cur;
dis[cnt]=1e18;
}
x=ch[x][*it];
}
return x;
}
void upd(vector<int> v,i64 c,int l)
{
int x=qid(v);
if(dis[x]>c){
dis[x]=c;lst[x]=l;
}
if(dis[x]==c){
lst[x]=max(lst[x],l);
}
}
int main()
{
//cerr<<sizeof(ch)/1048576<<endl;
read(t);fz1(i,t){read(n[i]);fz1(j,n[i])read(a[i][j]);lim=max(lim,n[i]);}
upd({0},0,0);
fz1(_,lim)for(int x:f[_]){
i64 cur=dis[x]*2;
vector<int> v=seq[x];
vector<int> nv=v;
fz0k(i,v.size()){
if(x!=1) cur+=2;nv.push_back(v[i]+1);int j=nv.size()-1;
if(nv.size()>lim) break;
while(j&&nv[j]<nv[j-1])swap(nv[j],nv[j-1]),j--;
if(i>=lst[x]) upd(nv,cur,i);
}
}
//cerr<<cnt<<endl;
fz1(k,t){
ans=1e18;sort(a[k]+1,a[k]+n[k]+1);
if(n[k]==1){puts("0");continue;}
for(int i:f[n[k]]){
i64 sum=dis[i];
// cerr<<dis[i]<<endl;ff(seq[i],it) cerr<<*it<<' ';cerr<<endl;
fz1(j,n[k]) sum+=1ll*a[k][j]*seq[i][n[k]-j];
ans=min(ans,sum);
}
printf("%lld\n",ans-(n[k]-2));
}
return 0;
}