有 个点,每个点有权值 和 。
点 到点 的有向边边权为 ,找到一条从 出发,经过每个点恰好一次,最后回到 的路径,使其最大边权最小。
,。
问题相当于每个点有一个入边 和出边 ,求最大边权最小的哈密顿回路。
考虑下界,忽略需要成环的条件,则肯定将 和 分别排序后按位置一一匹配,这样是最优的。
这样会形成若干个环,考虑调整匹配使得这些环合并成一个大环。调整匹配的操作一定形如选取一对 ,交换 ,将匹配从 变为 ,而这会合并相邻的两个环。注意到由于要求最大值最小,所以一定有 ,否则可以将 内的环依次合并,一定不劣。
那么类似最小生成树,将 对 产生的贡献放到一起排序,每次选贡献最小的交换即可。
代码如下(题面不太一样):
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
template<typename T>
inline void read(T &x)
{
char c=getchar();
x=0;
T w=1;
while(c<'0'||c>'9') w=(c=='-'?-w:w),c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
x*=w;
}
typedef long long ll;
const int S=1000005,M=32767;
int n,a[S],b[S];
pair<int,int> ta[S],tb[S];
int fa[S];
pair<ll,pair<int,int> > ed[S];
inline void getin(int a[])
{
int x,y,z;
read(a[1]),read(a[2]),read(x),read(y),read(z);
for(int i=3;i<=n;i++) a[i]=(a[i-1]*x%M+a[i-2]*y%M+z)%M;
}
int fnd(int x){return fa[x]==x?x:fa[x]=fnd(fa[x]);}
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
read(n);
getin(a),getin(b);
for(int i=1;i<=n;i++)
{
ta[i]=make_pair(a[i],i);
tb[i]=make_pair(b[i],i);
}
sort(ta+1,ta+n+1);
sort(tb+1,tb+n+1);
for(int i=1;i<=n;i++) fa[i]=i;
ll ans=0;
for(int i=1;i<=n;i++)
{
int x=ta[i].second,y=tb[i].second;
fa[fnd(x)]=fnd(y);
ans=max(ans,1ll*a[x]*a[x]-1ll*b[y]*b[y]);
}
for(int i=1;i<=n-1;i++)
{
int xi=ta[i].second,yi=tb[i].second;
int xj=ta[i+1].second,yj=tb[i+1].second;
ed[i]=make_pair(max(
1ll*a[xi]*a[xi]-1ll*b[yj]*b[yj],
1ll*a[xj]*a[xj]-1ll*b[yi]*b[yi]),
make_pair(xi,yj));
}
sort(ed+1,ed+n);
for(int i=1;i<=n-1;i++)
{
ll w=ed[i].first;
int x=ed[i].second.first,y=ed[i].second.second;
if(fnd(x)==fnd(y)) continue;
ans=max(ans,w);
fa[fnd(x)]=fnd(y);
}
printf("%lld\n",ans);
return 0;
}