https://codeforces.com/problemset/problem/1343/F
感觉这种2400分的题还比较适合刷,一般要做个1个多2个小时,但是要在比赛的时候能做出来的话,应该要能再半小时之内做出来才行。
这题首先想到,r=2的时候l=1,那么能做开头的数字是哪些就有限制了,必须是长度为2的序列中的。
然后我们可以算一个dis[i][j]表示i离j最远距离的最小值是多少,如果一个[l,r]长度是len,那么他们中间的元素之间相差的距离最多是len-1了,很多个区间中出线过,那就取最小值。所以直接枚举每一个开头st,看以这个数字开头能不能构造出合法序列,然后枚举每一个位置i,再找出之前已经填了的位置中数字当前剩下的数字中离他们最远距离最小的是哪个,然后取个最小的填到当前位置i。
然后这样尝试后发现过了样例,然而交上去又wa3由wa4
结果还是没想清楚,看了数据以后才明白,关键是由于每个区间r是独立的,也就是对于[l1,r-1]转移到[l2,r]这个区间时,从[l2,r-1]这个区间的数字必须把ans[r]这个数字给确定放在r这个位置才行,那么每次取出最远距离最小的必须等于i,才是合法序列
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=210;
int n,m,cas,cnt,tot;
int a[maxl][maxl],len[maxl],ans[maxl];
int dis[maxl][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
struct node
{
int dis,id;
bool operator > (const node &b)const
{
return dis>b.dis;
}
}mi[maxl];
priority_queue<node,vector<node>,greater<node>> q[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
dis[i][j]=maxl;
dis[i][i]=0;in[i]=false;
}
for(int i=1;i<=n-1;i++)
{
scanf("%d",&len[i]);
for(int j=1;j<=len[i];j++)
scanf("%d",&a[i][j]);
if(len[i]==2)
in[a[i][1]]=1,in[a[i][2]]=1;
for(int j=1;j<=len[i];j++)
for(int k=1;k<=len[i];k++)
dis[a[i][j]][a[i][k]]=min(dis[a[i][j]][a[i][k]],len[i]-1);
}
}
inline void init()
{
for(int i=1;i<=n;i++)
{
while(!q[i].empty()) q[i].pop();
vis[i]=false;
for(int j=1;j<=n;j++)
if(j!=i)
q[i].push(node{dis[i][j],j});
}
}
inline void mainwork()
{
bool flag;int mn;node d;
for(int st=1;st<=n;st++)
if(in[st])
{
init();
ans[1]=st;flag=true;vis[st]=true;
for(int j=1;j<=n;j++)
while(!q[j].empty() && vis[q[j].top().id])
q[j].pop();
for(int i=2;i<=n;i++)
{
mn=maxl;
for(int j=1;j<=i-1;j++)
if(!q[ans[j]].empty())
mi[j]=q[ans[j]].top();
for(int j=1;j<=i-1;j++)
{
if(q[ans[j]].empty()) continue;
if(mn>mi[j].dis+j)
{
mn=mi[j].dis+j;
d=mi[j];
}
}
if(mn!=i)
{
flag=false;
break;
}
ans[i]=d.id;vis[d.id]=true;
for(int j=1;j<=n;j++)
while(!q[j].empty() && vis[q[j].top().id])
q[j].pop();
}
if(flag)
{
//puts("ok");
return;
}
}
}
inline void print()
{
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],(i==n)?'\n':' ');
}
int main()
{
int t=1;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}