题解 一道计算几何的模板题
嗯。
-
关于 Graham 算法求凸包的一些实现细节:
选取最左上的点为基准点(定义为横坐标最小的点,如有相同选纵坐标最大的)
注意若逆时针扫描,只有选最左上的点是正确的而选最左下不正确
当按极角序排序时,若当前比较的两点横坐标相同纵坐标小的在前,若极角相等模长小的在前点我送凸包板子
namespace convex{ int top; double ans; const double eps=1e-9; pair<double, double> a[N], sta[N]; struct vec{double x, y; vec(double a, double b):x(a),y(b){}}; inline double operator ^ (vec a, vec b) {return a.x*b.y-b.x*a.y;} inline double dis(pair<double, double> a, pair<double, double> b) { return sqrt((a.fir-b.fir)*(a.fir-b.fir)+(a.sec-b.sec)*(a.sec-b.sec)); } inline bool isect(pair<double, double> a, pair<double, double> b, pair<double, double> c) { return (vec(c.fir-a.fir, c.sec-a.sec)^vec(b.fir-a.fir, b.sec-a.sec))>=0; } inline double area(pair<double, double> a, pair<double, double> b, pair<double, double> c) { double x=dis(a, b), y=dis(b, c), z=dis(a, c), p=(x+y+z)/2; // cout<<"xyz: "<<fixed<<setprecision(5)<<x<<' '<<y<<' '<<z<<endl; return round(sqrt(p*(p-x)*(p-y)*(p-z))*2); } double solve(int n) { sort(a+1, a+n+1, [](pair<double, double> x, pair<double, double> y){ return fabs(x.fir-y.fir)<eps?x.sec<y.sec:x.fir<y.fir; }); n=unique(a+1, a+n+1)-a-1; sort(a+2, a+n+1, [](pair<double, double> x, pair<double, double> y){ if (x.fir==y.fir) return x.sec<y.sec; double tem=vec(x.fir-a[1].fir, x.sec-a[1].sec)^vec(y.fir-a[1].fir, y.sec-a[1].sec); if (fabs(tem)<eps) return dis(a[1], x)<dis(a[1], y); else return tem>0; }); // cerr<<"a: "; for (int i=1; i<=n; ++i) cerr<<"("<<a[i].fir<<','<<a[i].sec<<") "; cerr<<endl; for (int i=1; i<=n; ++i) { while (top>1 && isect(sta[top-1], sta[top], a[i])) --top; sta[++top]=a[i]; } // cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cout<<endl; // for (int i=3; i<=top; ++i) ans+=area(sta[1], sta[i-1], sta[i]); //, cout<<"area: "<<area(sta[1], sta[i-1], sta[i])<<endl; for (int i=2; i<=top; ++i) ans+=dis(sta[i-1], sta[i]); ans+=dis(sta[1], sta[top]); // sort(sta+1, sta+top+1); // cerr<<"sta: "; for (int i=1; i<=top; ++i) cerr<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cerr<<endl; return ans; } }
本来还有几组 hack 数据的但是被我重启弄丢了
然后回到本题
发现 \(x\) 的循环节 \(k\) 是 \(O(n)\) 级别的
发现能与 \(x\) 匹配的 \(y\) 是在 \(y\) 上以 \(k\) 为步长能跳到的所有点
发现只关心能跳到的最大,最小 \(y\)
发现在同一个跳的过程中构成的环上的点最大,最小相同
所以可以做到 \(O(n)\),需要处理大量边界情况
但因为数据是随的 \(O(n^2)\) 且完全不做任何处理也能过
点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 400010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll n;
ll x[N], y[N];
ll ax, ay, bx, by, px, py, kx;
namespace convex{
ll ans;
int top;
pair<ll, ll> a[N], sta[N];
struct vec{ll x, y; vec(ll a, ll b):x(a),y(b){}};
inline ll operator ^ (vec a, vec b) {return a.x*b.y-b.x*a.y;}
inline double dis(pair<ll, ll> a, pair<ll, ll> b) {
return sqrt((a.fir-b.fir)*(a.fir-b.fir)+(a.sec-b.sec)*(a.sec-b.sec));
}
inline bool isect(pair<ll, ll> a, pair<ll, ll> b, pair<ll, ll> c) {
return (vec(c.fir-a.fir, c.sec-a.sec)^vec(b.fir-a.fir, b.sec-a.sec))>=0;
}
inline double area(pair<ll, ll> a, pair<ll, ll> b, pair<ll, ll> c) {
double x=dis(a, b), y=dis(b, c), z=dis(a, c), p=(x+y+z)/2;
// cout<<"xyz: "<<fixed<<setprecision(5)<<x<<' '<<y<<' '<<z<<endl;
return round(sqrt(p*(p-x)*(p-y)*(p-z))*2);
}
ll solve(int n) {
sort(a+1, a+n+1, [](pair<ll, ll> x, pair<ll, ll> y){
return x.fir==y.fir?x.sec<y.sec:x.fir<y.fir;
});
n=unique(a+1, a+n+1)-a-1;
sort(a+2, a+n+1, [](pair<ll, ll> x, pair<ll, ll> y){
if (x.fir==y.fir) return x.sec<y.sec;
ll tem=vec(x.fir-a[1].fir, x.sec-a[1].sec)^vec(y.fir-a[1].fir, y.sec-a[1].sec);
if (!tem) return dis(a[1], x)<dis(a[1], y);
else return tem>0;
});
// cerr<<"a: "; for (int i=1; i<=n; ++i) cerr<<"("<<a[i].fir<<','<<a[i].sec<<") "; cerr<<endl;
for (int i=1; i<=n; ++i) {
while (top>1 && isect(sta[top-1], sta[top], a[i])) --top;
sta[++top]=a[i];
}
// cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cout<<endl;
for (int i=3; i<=top; ++i) ans+=area(sta[1], sta[i-1], sta[i]); //, cout<<"area: "<<area(sta[1], sta[i-1], sta[i])<<endl;
// sort(sta+1, sta+top+1);
// cerr<<"sta: "; for (int i=1; i<=top; ++i) cerr<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cerr<<endl;
return ans;
}
}
namespace force{
void solve() {
for (int i=1; i<n; ++i) {
x[i]=(ax*x[i-1]+bx)%px;
y[i]=(ay*y[i-1]+by)%py;
}
for (int i=0; i<n; ++i) convex::a[i+1]={x[i], y[i]};
cerr<<"x: "; for (int i=0; i<n; ++i) cerr<<x[i]<<' '; cerr<<endl;
cerr<<"y: "; for (int i=0; i<n; ++i) cerr<<y[i]<<' '; cerr<<endl;
printf("%lld\n", convex::solve(n));
}
}
namespace task1{
int vis[N];
vector<int> sta;
int siz, loop, top;
pair<int, int> range;
int nxt[N], jmp[N], str[N];
void solve() {
siz=loop=n; range={0, n-1};
memset(vis, -1, sizeof(vis));
memset(jmp, -1, sizeof(jmp));
memset(nxt, -1, sizeof(nxt));
vis[x[0]]=0;
for (int i=1; i<n; ++i) {
x[i]=(ax*x[i-1]+bx)%px;
if (~vis[x[i]]) {
siz=i-vis[x[i]];
range={vis[x[i]], i-1};
for (int j=0; j<vis[x[i]]; ++j) {
if (j) y[j]=(ay*y[j-1]+by)%py;
convex::a[++top]={x[j], y[j]};
}
break;
}
else vis[x[i]]=i;
}
// cerr<<"siz: "<<siz<<endl;
memset(vis, -1, sizeof(vis));
vis[y[0]]=0;
for (int i=1; i<n; ++i) {
y[i]=(ay*y[i-1]+by)%py;
nxt[y[i-1]]=y[i];
if (~vis[y[i]]) {loop=i-vis[y[i]]; break;}
else vis[y[i]]=i;
}
// cerr<<"loop: "<<loop<<endl;
// cerr<<"top: "<<top<<endl;
ll now=y[0]; str[0]=now;
for (int i=1; i<=siz; ++i) str[i]=now=(ay*now+by)%py;
for (int i=siz+1; i<=range.sec; ++i) str[i]=(ay*str[i-1]+by)%py;
// cerr<<"str: "; for (int i=0; i<py; ++i) cerr<<str[i]<<' '; cerr<<endl;
// cerr<<"nxt: "; for (int i=0; i<py; ++i) cerr<<nxt[i]<<' '; cerr<<endl;
jmp[y[0]]=now;
memset(vis, 0, sizeof(vis));
sta.clear(); vis[y[0]]=1; sta.pb(y[0]);
for (int pos=nxt[y[0]]; !vis[pos]&&pos!=-1; pos=nxt[pos])
jmp[pos]=now=(ay*now+by)%py, vis[pos]=1, sta.pb(pos);
while (sta.size()) vis[sta.back()]=0, sta.pop_back();
// cerr<<"id : "; for (int i=0; i<py; ++i) cerr<<i<<' '; cerr<<endl;
// cerr<<"jmp: "; for (int i=0; i<py; ++i) cerr<<jmp[i]<<' '; cerr<<endl;
// cerr<<"range: "<<range.fir<<' '<<range.sec<<endl;
for (int i=range.fir; i<=range.sec; ++i) {
// cerr<<"at "<<i<<endl;
ll maxy=str[i], miny=str[i];
sta.clear(); vis[str[i]]=1; sta.pb(str[i]);
for (ll y=jmp[str[i]],tim=i+siz; !vis[y]&&tim<n; y=jmp[y],tim+=siz)
maxy=max(maxy, y), miny=min(miny, y), vis[y]=1, sta.pb(y); //, cerr<<"y="<<y<<endl;
while (sta.size()) vis[sta.back()]=0, sta.pop_back();
// cerr<<"add: ("<<x[i]<<','<<miny<<")"<<endl;
// cerr<<"add: ("<<x[i]<<','<<maxy<<")"<<endl;
convex::a[++top]={x[i], miny};
convex::a[++top]={x[i], maxy};
}
printf("%lld\n", convex::solve(top));
}
}
signed main()
{
freopen("geometry.in", "r", stdin);
freopen("geometry.out", "w", stdout);
x[0]=read(); y[0]=read(); ax=read(); ay=read(); bx=read(); by=read(); px=read(); py=read(); n=read();
// force::solve();
task1::solve();
// n=read();
// for (int i=1; i<=n; ++i) {
// int x=read(), y=read();
// convex::a[i]={x, y};
// }
// convex::solve(n);
return 0;
}