20220728
一道计算几何的模板题
点很多值域很小,考虑对每个横坐标求出最大/最小的纵坐标,只有这些点可能在凸包上
递推 \(O(p)\) 次后会进入循环节,前面的暴力。之后对于固定的 \(x_i\) 而言,只有前 \(py\) 个对应的 \(y\) 有用。把对应的 \(y\) 集合相同的 \(x_i\) 一起计算,相当于求 RMQ(这部分还是看码比较直观)
时间复杂度线性对数
赛时代码
const int inf = 0x3f3f3f3f;
struct Vec {
LL x,y; Vec(LL x=0,LL y=0):x(x),y(y){}
bool operator < (const Vec &a) const { return x!=a.x ? x<a.x : y<a.y; }
friend bool operator == (const Vec &a,const Vec &b) { return !(a<b||b<a); }
Vec operator - (const Vec &a) const { return {x-a.x,y-a.y}; }
LL operator & (const Vec &a) const { return x*a.y-y*a.x; }
};
const int N = 4e5+5;
int n,ax,ay,bx,by,px,py,qx,qy,x[N],y[N],mx[N],mn[N];
LL m;
bool vis[N];
Vec p[N];
int stk[N],tp;
struct {
int tn,t[N*4];
void bld(const Vi &p) {
tn = 1 << __lg(sz(p)+1)+1;
memset(t,0,sizeof(int)*tn*2);
Rep(i,0,sz(p)) t[tn+i+1] = y[p[i]];
rFor(i,tn,1) t[i] = max(t[i<<1],t[i<<1|1]);
}
int qry(int l,int r) {
int res = 0;
for(l += tn, r += tn+2; l^r^1; l >>= 1, r >>= 1) {
if( ~l & 1 ) ckmax(res,t[l^1]);
if( r & 1 ) ckmax(res,t[r^1]);
}
return res;
}
} t1;
struct {
int tn,t[N*4];
void bld(const Vi &p) {
tn = 1 << __lg(sz(p)+1)+1;
memset(t,0x3f,sizeof(int)*tn*2);
Rep(i,0,sz(p)) t[tn+i+1] = y[p[i]];
rFor(i,tn,1) t[i] = min(t[i<<1],t[i<<1|1]);
}
int qry(int l,int r) {
int res = inf;
for(l += tn, r += tn+2; l^r^1; l >>= 1, r >>= 1) {
if( ~l & 1 ) ckmin(res,t[l^1]);
if( r & 1 ) ckmin(res,t[r^1]);
}
return res;
}
} t2;
signed main() {
#ifdef FS
freopen("geometry2.in","r",stdin); freopen("geometry.out","w",stdout);
#else
freopen("geometry.in","r",stdin); freopen("geometry.out","w",stdout);
#endif
memset(mn,0x3f,sizeof mn);
ios::sync_with_stdio(0);cout.tie(0);
io>>x[1]>>y[1]>>ax>>ay>>bx>>by>>px>>py>>m;
int mm = min((LL)2e5,m);
For(i,2,mm) x[i] = ((LL)ax*x[i-1]+bx) %px, y[i] = ((LL)ay*y[i-1]+by) %py;
For(i,1,mm) ckmax(mx[x[i]],y[i]), ckmin(mn[x[i]],y[i]);
m -= mm, x[0] = x[mm], y[0] = y[mm];
for(int i = 1; ; ++i) {
x[i] = ((LL)ax*x[i-1]+bx) %px;
if( x[i] == x[0] ) { qx = i; break; }
}
for(int i = 1; ; ++i) {
y[i] = ((LL)ay*y[i-1]+by) %py;
if( y[i] == y[0] ) { qy = i; break; }
}
Rep(i,0,qy) if( !vis[i] ) {
Vi p;
int j = i; do p.pb(j), vis[j] = 1, j = (j+qx)%qy; while( j != i );
p.insert(p.end(),all(p)), t1.bld(p), t2.bld(p);
Rep(l,0,sz(p)/2) for(j = p[l]; j < qx; j += qy) {
if( j > m ) break;
int r = min(sz(p)-1ll,l+(m-j)/qx);
ckmax(mx[x[j]],t1.qry(l,r)), ckmin(mn[x[j]],t2.qry(l,r));
}
}
Rep(i,0,px) if( mn[i] < inf ) p[++n] = {i,mx[i]}, p[++n] = {i,mn[i]};
sort(p+1,p+n+1), n = unique(p+1,p+n+1)-p-1;
auto push=[&](int i) {
while( tp > 1 && (p[i]-p[stk[tp-1]] & p[stk[tp]]-p[stk[tp-1]]) > 0 )
vis[stk[tp--]] = 0;
vis[i] = 1, stk[++tp] = i;
};
memset(vis,0,sizeof vis);
stk[++tp] = 1; For(i,2,n) push(i); rFor(i,n,1) if( !vis[i] ) push(i);
LL ans=0; Rep(i,1,tp) ans += p[stk[i]] & p[stk[i+1]];
cout<<ans;
return 0;
}
菜肴挑选
不知道如何想到,所以只能生硬的给做法了
- \(n\) 是奇数:把 \(n\) 个点等距离的放到圆上,枚举所有等腰三角形。这样任意一对点会被作为底边枚举 \(1\) 次,腰枚举 \(2\) 次
- \(n\) 是偶数:拿前 \(n-1\) 个点做上述过程。猜想最终每条边算了\(6\) 次。可以对前 \(n-1\) 个点中距离为 \(1\) 的点 \(x,y\) 算 \(2\) 次 \((x,y,n)\),距离为 \(2\) 的点 \(x,y\) 算 \(1\) 次 \((x,y,n)\)。此时 \(n\) 与其他点都算了 \(6\) 次,前 \(n-1\) 个点中距离为 \(1\) 的算了 \(5\) 次,距离为 \(2\) 的算了 \(4\) 次,其余算了 \(3\) 次。在枚举所有腰长 \(>1\) 的等腰三角形即可
code
const int N = 1e3+5;
int n,m;
vector<tuple<int,int,int>> ans;
signed main() { freopen("dish.in","r",stdin); freopen("dish.out","w",stdout);
io>>n, m = n-(~n&1);
For(i,1,m) For(j,i+1,m)
if( j-i & 1 ) {
int k = j + (m-(j-i))/2;
if( k > m ) k -= m;
ans.pb(i,j,k);
} else ans.pb(i,j,i+j>>1);
if( ~n & 1 ) {
For(i,1,m) ans.pb(i,i%m+1,n), ans.pb(i,i%m+1,n);
For(i,1,m) ans.pb(i,(i+1)%m+1,n);
For(i,1,m) For(j,2,m/2) {
int x = i-j, y = i+j;
if( x < 1 ) x += m;
if( y > m ) y -= m;
ans.pb(i,x,y);
}
}
io<<sz(ans)<<endl;
for(auto &i : ans) io<<get<0>(i)<<' '<<get<1>(i)<<' '<<get<2>(i)<<endl;
return 0;
}
异或矩阵
crashed
对于这种构造方式较简单但数据规模很大的东西可以找一些倍增/递归的性质
打表找规律固然直观,但也不能忽视了宏观的把控
code
LL L,R,mx;
mint ans;
#define mid (l+r>>1)
void dfs(LL l,LL r,bool wh) {
if( L <= l && r <= R ) {
auto upd=[](LL x,mint y) {
if( x > mx ) mx = x, ans = 0;
if( x == mx ) ans += y;
};
int k = __lg(r-l+1); // r-l+1 = pow(2,k)
upd(r-l,Pow(2,2*k));
if( !wh ) {
if( r < R ) upd((r-l)*2+1,2*Pow(2,k)*(R-r));
} else {
if( L < l ) upd((r-l)*2+1,2*Pow(2,k)*(l-L));
}
return;
}
if( L <= mid ) dfs(l,mid,0);
if( mid < R ) dfs(mid+1,r,1);
}
void MAIN() {
io>>L>>R;
dfs(0,(1ll<<60)-1,0);
io<<mx<<' '<<ans.x<<endl;
} signed main() { freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout);
int T=read(); while( T-- ) MAIN(), mx = ans.x = 0;
return 0;
}
官方题解
写个暴力发现答案是 \(2^{k}-1\)。若答案至少是 \(2^k\),那么存在两个格子分别为 \(2^{k}-1,2^{k}\),分类讨论:
- 为 \((x,y),(x+1,y)\):由 \(x\oplus y=2^{k}-1,x+1\oplus y=2^{k}\) 可得 \(x\oplus x+1=2^{k+1}-1\),因此 \(x=A2^{k+1}+2^{k}-1,y=A2^{k+1}\)。存在这样的 \(x,y\) 的限制条件为 \(L\le y<x<R\)。\(L\le A2^{k+1}\le R-2^{k}\Rightarrow L\le R-2^{k}-((R-2^{k})\bmod2^{k+1})\)
- 为 \((x,y),(x-1,y)\):同理可得 \(x=A2^{k+1}+2^{k},y=A2^{k+1}+2^{k+1}-1\),\(L+2^{k}\le R-((R+1)\bmod2^{k+1})\)
找到满足条件的最大 \(k\),答案就是 \(2^{k+1}-1\)
计数部分没看懂