题面
一句话题意:给定平面上 n n n 个整点,求构成的凸包面积大小乘 2 的值。
数据生成方式:
给定
x
0
,
y
0
,
a
x
,
a
y
,
b
x
,
b
y
,
p
x
,
p
y
,
n
x_0,y_0,a_x,a_y,b_x,b_y,p_x,p_y,n
x0,y0,ax,ay,bx,by,px,py,n ,
x
i
=
(
a
x
x
i
−
1
+
b
x
)
m
o
d
p
x
y
i
=
(
a
y
y
i
−
1
+
b
y
)
m
o
d
p
y
x_i=(a_xx_{i-1}+b_x)\mod p_x\\ y_i=(a_yy_{i-1}+b_y)\mod p_y
xi=(axxi−1+bx)modpxyi=(ayyi−1+by)modpy
最后得到 n n n 个点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , . . . , ( x n − 1 , y n − 1 ) (x_0,y_0),(x_1,y_1),...,(x_{n-1},y_{n-1}) (x0,y0),(x1,y1),...,(xn−1,yn−1) 。
n ≤ 1018
px,py ≤ 200000
题解
我们发现这个 n 特别大,但是坐标值域比较小。
相信每个做过平面凸包的人都有过这样一个梦想:将横坐标每一个值对应的最小纵坐标和最大纵坐标求出来,当成两个序列做斜率优化求凸包。但是无奈值域通常是非常大的,这个想法一般用不了。
这道题就不一样了,至于比较小,我们完全可以求每一个横坐标对应的最小纵坐标和最大纵坐标。
根据鸽笼原理,n 特别大的时候横坐标和纵坐标一定会形成循环。
我们求出每一个纵坐标第一次出现的时刻(可以这么说吧)和第二次出现的时刻(如果有的话),然后从小到大/从大到小枚举纵坐标给横坐标赋值。由于不难发现只会形成一个循环,所以每个位置的第二时刻和第一时刻的差都是相等的。
我们对于每个纵坐标枚举对应的横坐标,暴力赋值,这其中需要跳过已经赋值过的横坐标。由于不管纵坐标是什么,相同纵坐标的下一个横坐标是仅取决于当前横坐标的,所以我们可以用并查集维护已经赋值过的连续段,确保可以 O ( log p ) O(\log p) O(logp) 跳过。
时间复杂度 O ( p log p ) O(p\log p) O(plogp) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#pragma GCC optimize(2)
using namespace std;
#define MAXN 200005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define PR pair<int,int>
#define UIN unsigned int
#define SQ 317
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
// #define getchar() xchar()
inline LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
inline void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
inline void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int l[MAXN],r[MAXN];
int P = 1;
struct it{
int a,b;LL c;
it(){a=1;b=0;c=0;}
it(int A,int B,LL C){a=A;b=B;c=C;}
}kx[MAXN],ky[MAXN];
inline it operator * (it l,it r) {
l.a = l.a*1ll*r.a % P;
l.b = (l.b*1ll*r.a + r.b) % P;
l.c += r.c; return l;
}
inline int operator * (int x,it y) {
return (x*1ll*y.a + y.b) % P;
}
PR fr[MAXN];
it la[MAXN];
int fa[MAXN];
it fe[MAXN];
int findf(int x) {
if(x == fa[x]) return x;
int r = fa[x],f = findf(r);
fe[x] = fe[x]*fe[r]; fa[x] = f;
return f;
}
void unionSet(int u,int f,it k) {
fa[u] = findf(f); fe[u] = k*fe[f];
}
PR ar[MAXN<<1];
int ca;
int st[MAXN],tp;
LL S(PR a,PR b,PR c) {
PR A = {a.FI-b.FI,a.SE-b.SE};
PR B = {c.FI-b.FI,c.SE-b.SE};
LL rs = A.SE*1ll*B.FI - A.FI*1ll*B.SE;
return rs<0 ? -rs:rs;
}
int main() {
freopen("geometry.in","r",stdin);
freopen("geometry.out","w",stdout);
int x0 = read(),y0 = read();
int ax = read(),ay = read();
int bx = read(),by = read();
it tx = it(ax,bx,1),ty = it(ay,by,1);
n = read();m = read();
LL N = read();
P = n;
for(int i = 1;i < n;i ++) kx[i] = kx[i-1]*tx;
P = m;
for(int i = 1;i < m;i ++) ky[i] = ky[i-1]*ty;
for(int i = 0;i < n;i ++) {
l[i] = m+1; r[i] = -1;
fa[i] = i; fe[i] = it();
}
P = m;
int p = y0,ct = 0,xx = x0;
while(!la[p].c && ct < N) {
if(!fr[p].FI) {
fr[p] = {ct+1,xx};
}
else if(!la[p].c) {
la[p] = kx[ct-fr[p].FI+1];
}
p = p*ty; ct ++;
P = n; xx = xx*tx; P = m;
}
P = n;
for(int i = 0;i < m;i ++) {
if(fr[i].FI) {
int p = fr[i].SE;
LL cn = fr[i].FI-1;
findf(p); cn += fe[p].c;
p = fa[p];
while(cn < N) {
l[p] = min(l[p],i);
r[p] = max(r[p],i);
if(!la[i].c) break;
int nx = p*la[i];
if(findf(nx) == p) break;
unionSet(p,nx,la[i]);
findf(p); cn += fe[p].c;
p = fa[p];
}
}
}
for(int i = 0;i < n;i ++) fa[i] = i,fe[i] = it();
for(int i = m-1;i >= 0;i --) {
if(fr[i].FI) {
int p = fr[i].SE;
LL cn = fr[i].FI;
findf(p); cn += fe[p].c;
p = fa[p];
while(cn <= N) {
l[p] = min(l[p],i);
r[p] = max(r[p],i);
if(!la[i].c) break;
int nx = p*la[i];
if(findf(nx) == p) break;
unionSet(p,nx,la[i]);
findf(p); cn += fe[p].c;
p = fa[p];
}
}
}
int ll = n-1,rr = 0;
for(int i = 0;i < n;i ++) {
if(l[i] < n && r[i] >= 0) {
ll = min(ll,i); rr = max(rr,i);
}
}
tp = 0;
for(int i = ll;i <= rr;i ++) {
if(l[i] >= n || r[i] < 0) continue;
while(tp > 1 && (l[st[tp]]-l[st[tp-1]])*1ll*(i-st[tp]) >= (l[i]-l[st[tp]])*1ll*(st[tp]-st[tp-1])) {
st[tp --] = 0;
}
st[++ tp] = i;
}
for(int i = 1;i <= tp;i ++) {
ar[++ ca] = {st[i],l[st[i]]};
}
tp = 0;
for(int i = ll;i <= rr;i ++) {
if(l[i] >= n || r[i] < 0) continue;
while(tp > 1 && (r[st[tp]]-r[st[tp-1]])*1ll*(i-st[tp]) <= (r[i]-r[st[tp]])*1ll*(st[tp]-st[tp-1])) {
st[tp --] = 0;
}
st[++ tp] = i;
}
for(int i = tp;i > 0;i --) {
ar[++ ca] = {st[i],r[st[i]]};
}
LL ans = 0;
for(int i = 3;i <= ca;i ++) {
ans += S(ar[1],ar[i-1],ar[i]);
}
AIput(ans,'\n');
return 0;
}