对于每一个拨圈,分别考虑它对答案的影响。但注意到当前拨圈的最优转动方案会对之后的拨圈转动方案产生影响,即有后效性。
后效性的产生可以通过随机化改变考虑的顺序解决。
代码实现的一点细节:先考虑出每个圈的最优转动方案,更新在此方案下的当前局面每一行的最大值、最小值。把 n n n 个拨圈全部统计完之后更新当前考虑顺序下的答案。
注意到 random_shuffle
比 shuffle
更好地快速逼近答案。
#include
using namespace std;
const int maxn=5e4+5;
int a[maxn][5],mx[5],mi[5],T,k;
void solve()
{
int n;cin>>n;
for(int j=1;j<=k;j++) for(int i=1;i<=n;i++) cin>>a[i][j];
int tt=300,ans=0x3f3f3f;
while(tt--)
{
// mt19937 rd(time(0));
// shuffle(a+1,a+n+1,rd);
random_shuffle(a+1,a+n+1);
memset(mx,-0x3f3f3f,sizeof mx),memset(mi,0x3f3f3f,sizeof mi);
for(int i=1;i<=n;i++)
{
int minstp=0,minv=0x3f3f3f;
for(int stp=0;stp<k;stp++)
{
int vv=0;
for(int j=1;j<=k;j++)
{
int pos=(j+stp-1)%k+1;
vv=max(vv,max(mx[j],a[i][pos])-min(mi[j],a[i][pos]));
}
if(vv<minv) minstp=stp,minv=vv;
}
for(int j=1;j<=k;j++)
{
int nowpos=(j+minstp-1)%k+1;
mx[j]=max(mx[j],a[i][nowpos]),mi[j]=min(mi[j],a[i][nowpos]);
}
if(minv>=ans) break;//到当前局面松散度已经超过原答案
// cout<
}
int tmp=0;
for(int i=1;i<=k;i++) tmp=max(tmp,mx[i]-mi[i]);
ans=min(tmp,ans);
}
cout<<ans<<'\n';
}
int main()
{
cin>>T>>k;
while(T--) solve();
return 0;
}