BZOJ 2139 road
题意
很久很久以前,中原地区分成了N个国家,编号为1到N,任意两个国家都可互达。每个国家有一个攻击值(A[i])和防御值(B[i])。定义一个人从i国去j国的危险值为:假如(A[i]>B[j]),则危险值为(( A[i]^2-B[j]^2)),否则危险值为0。现在,Nan从国家1出发,经过每一个国家有且仅有一次,最后回到国家1,要求找出一种方案,使得其中危险值的最大值最小。
题解
感觉网上的题解好少啊,实际上想通了似乎发现这题还是比较的好写的,不过仍然还是一道十分妙妙的题目。在看到我们现将所有国家的(a)与(b)开来,然后我们分别按他们的值从小到大排序,然后先贪心的进行连边。这个时候,我们的连边方式一定是从(a_i)属于的那个国家连向(b_i)属于的那个国家,因为这样可以保证连出来的边危险值的最大值最小(这个可以意会一下)。这样我们就会得到许多小环,然后我们的目的就是把这些小环连成一个大环。所以我们考虑在这些环上加边,由于我们还要保证环之间的边能够尽量的小,所以我们在环之间的边一定是从(a_i)属于的那个国家连向(b_{i-1})属于的那个国家(因为如果连向(b_{i+1})所属的国家的话,那么(a_n)连向的国家一定是(b_1)所属的国家,那样就没有之前那种方案连那么优了)知道这个之后我们就可以对这些环做最小生成树了,每次连边的时候更新一下答案就行了,复杂度为(O(nlogn))。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('
');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
const int N=1e6+500;
const int Md=32767;
struct country {
int idx,v;
bool operator < (const country &rhs) const {
return v<rhs.v;
}
}a[N],b[N],c[N];
int n,x,y,z;
int fa[N];
int ans;
/*==================Define Area================*/
int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);}
int Sqr(int x) {return x*x;}
int main() {
read(n);
read(a[1].v);read(a[2].v);read(x);read(y);read(z);
for(int i=3;i<=n;i++) a[i].v=((ll)x*a[i-1].v+(ll)y*a[i-2].v+z)%Md;
read(b[1].v);read(b[2].v);read(x);read(y);read(z);
for(int i=3;i<=n;i++) b[i].v=((ll)x*b[i-1].v+(ll)y*b[i-2].v+z)%Md;
for(int i=1;i<=n;i++) fa[i]=a[i].idx=b[i].idx=i;
sort(a+1,a+1+n);sort(b+1,b+1+n);
for(int i=1;i<=n;i++) {
ans=max(ans,Sqr(a[i].v)-Sqr(b[i].v));
fa[Find(a[i].idx)]=Find(b[i].idx);
}
for(int i=2;i<=n;i++) {
c[i].v=Sqr(a[i].v)-Sqr(b[i-1].v);c[i].idx=i;
}
sort(c+1,c+n);
for(int i=1;i<n;i++) {
int fx=Find(a[c[i].idx].idx),fy=Find(b[c[i].idx-1].idx);
if(fx!=fy) ans=max(ans,c[i].v),fa[fx]=fy;
}
printf("%d
",ans);
return 0;
}