题意:输入b[3]...b[n],表示n,n-1,n-2位置的中位数,求构造一个序列。
题解给出一个结论是如果有解,那么a[i]必可以是可以受他影响的三个中位数中的一个。反证法:如果a[i]不是这三个中的其中一个,简单分析可知,必然有a[i] 大于这三个的最大值或者小于他们的最小值,那么显然把这个值调为最大值或者最小值,不会影响三个中位数。
这样很有道理,就可以DP了,令影响a[i]的三个数字位v[i][0-2],f[i][j][k]表示a[i]=v[i][j],a[i-1]=v[i-1][k]是否有可行解,于是我们每次枚举f[i][j][k]和f[i-1][k][l],是否能转移过来的条件就是f[i-1][k][l]=1且mid{v[i][j],v[i-1][k],v[i-2][l]}=b[i]。同时记录是由哪一个l转移过来的,方便最后找出一组解
初始化,必有a[1]=b[3]不会对后面造成任何影响,所以令v[1][0..2]=b[3],前2位是随便怎样都可行的,f[2][0..2][0..2]=1。
#include<bits/stdc++.h>
#define maxl 100010
using namespace std;
int n;
int b[maxl];
int v[maxl][3],f[maxl][3][3],pre[maxl][3][3];
bool flag;
int ans[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=3;i<=n;i++)
scanf("%d",&b[i]);
b[2]=b[1]=b[3];
b[n+1]=b[n+2]=b[n];
v[1][0]=v[1][1]=v[1][2]=b[1];
for(int i=2;i<=n;i++)
v[i][0]=b[i],v[i][1]=b[i+1],v[i][2]=b[i+2];
for(int i=1;i<=n;i++)
sort(v[i],v[i]+2);
}
inline int sorta(int a,int b,int c)
{
if(a>b) swap(a,b);
if(a>c) swap(a,c);
if(b>c) swap(b,c);
return b;
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
f[i][j][k]=0,pre[i][j][k]=0;
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
f[2][j][k]=1;
for(int i=3;i<=n;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
for(int l=0;l<3;l++)
if(f[i-1][k][l])
{
if(sorta(v[i-2][l],v[i-1][k],v[i][j])==b[i])
{
f[i][j][k]=1;pre[i][j][k]=l;
break;
}
}
flag=false;int jj,kk,l;
for(int j=0;j<3 && !flag;j++)
for(int k=0;k<3;k++)
if(f[n][j][k])
{
jj=j;kk=k;
flag=true;
break;
}
if(!flag) return;
for(int i=n;i>=2;i--)
{
ans[i]=v[i][jj];
l=pre[i][jj][kk];
jj=kk;kk=l;
}
ans[1]=b[1];
}
inline void print()
{
if(!flag)
puts("-1");
else
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],(i==n)?'\n':' ');
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}
本文探讨了一种基于已知中位数构建原始序列的算法。通过动态规划方法,确保了构建过程的可行性,最终输出满足条件的完整序列。文章详细介绍了算法流程,包括预处理、主处理和结果输出步骤。
392

被折叠的 条评论
为什么被折叠?



