[省选联考 2024] 季风 题解

首先整理式子,把 \(x_i\)\(x_i'\) 分开。

  • \(\sum\limits_{i=0}^{m-1}x_i'=x-\sum\limits_{i=0}^{m-1}x_{i \bmod n}\)
  • \(\sum\limits_{i=0}^{m-1}y_i'=y-\sum\limits_{i=0}^{m-1}y_{i \bmod n}\)

看到 \(|x_i'|+|y_i'|\le k\),我们不妨将 \(x'\)\(y'\) 放到一起考虑。

  • \(\sum\limits_{i=0}^{m-1}(x_i'+y_i')=x-\sum\limits_{i=0}^{m-1}x_{i \bmod n}+y-\sum\limits_{i=0}^{m-1}y_{i \bmod n}\)

但是这个式子显然是不能囊括所有情况的。

例如,当 \(x-\sum\limits_{i=0}^{m-1}x_{i \bmod n}<0,y-\sum\limits_{i=0}^{m-1}y_{i \bmod n}>0\) 时,两者加在一起反倒会让目标距离更短,不一定合法。

思考我们关注的是什么,距离。坐标可正可负,但是走到目标所需的距离一定是非负整数。

于是我们给上式加上绝对值,变成凑距离的形式。同时,我们贪心地想,对于每个 \(i\)\((x_i'+y_i')\) 直接取 \(k\) 一定不劣,于是我们可以继续修改式子。

  • \(mk\ge|x-\sum\limits_{i=0}^{m-1}x_{i \bmod n}|+|y-\sum\limits_{i=0}^{m-1}y_{i \bmod n}|\)

但是单这样还不够,\(m\) 可能非常大,暴力枚举是无法承受的。

考虑到一个 \(x_i\)\(m\) 足够大时会重复出现多次,不妨令 \(m=qn+p\),再预处理 \(x,y\) 数组的前缀和 \(sx,sy\),可以化简式子。

  • \((qn+p)k\ge|x-sx_p-q\cdot sx_{n-1}|+|y-sy_p-q\cdot sy_{n-1}|\)

接下来就是恶心的分讨了。

不妨设 \(f_x(q)=|x-sx_p-q\cdot sx_{n-1}|,f_y(q)=|y-sy_p-q\cdot sy_{n-1}|\) 的函数值为 \(0\) 时分别有 \(\lfloor q\rfloor=xz,yz\)

\(f_x(q)\) 进行分讨:

  • \(0\le q\le xz\),此时 \(q\) 的增长给 \(f_x(q)\) 带来了负收益。

  • \(q>xz\),此时 \(q\) 的增长给 \(f_x(q)\) 带来了正收益。

\(f_y(q)\) 同理。

两个函数均呈先单调减后单调增的趋势(由于 \(q\ge0\) 所以有可能出现没有单调减的情况)。此时将两个函数组合,形成了三部分,内容是类似的。

我们需要实现一个函数 check(l,r,p,xd,yd) 能够求出在 \(l\le q\le r\)\(f_x(q)-f_x(q-1)=xd\cdot sx_{n-1},f_y(q)-f_y(q-1)=yd\cdot sy_{n-1}\) 时,\(q\) 的最小值。

根据函数传入的参数,我们可以知道当 \(q\to q+1\) 时,\(f_x(q)+f_y(q)\) 的增/减量为 \(\Delta=xd\cdot sx_{n-1}+yd\cdot sy_{n-1}\)

我们设 \(sum=(ln+p+1)k,bas=f_x(l)+f_y(l),R=q-l\)。则我们要求一个不等式 \(sum+nkR\ge bas+R\Delta\),最小的正整数解为 \(R=\lceil\dfrac{bas-sum}{nk-\Delta}\rceil\)

最后判断 \(l+R\) 是否出界即可。上述过程均是 \(\mathcal O(1)\) 的,我们 \(\mathcal O(n)\) 地枚举 \(p\) 并求出最小的 \(q\),最后的答案即为所有 \(p\) 中最小的 \(q\)

时间复杂度:\(\mathcal O(\sum n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 LL;
const ll maxn=1000007,ee=1000000000000000007ll;
ll n,k,xg,yg,X[maxn],Y[maxn],sx[maxn],sy[maxn],val[maxn],ans;
LL myabs(LL x){return (x>0?x:-x);}
ll checkseg(ll l,ll r,ll p,ll xd,ll yd){
	if(l>r) return ee;
	LL sum=((LL)l*n+p+1)*(LL)k,bas=myabs(xg-sx[p+1]-(LL)l*sx[n])+myabs(yg-sy[p+1]-(LL)l*sy[n]),delt=xd*sx[n]+yd*sy[n];
	if(bas<=sum) return l*n+p+1; if(delt>=(LL)n*k) return ee;
	LL res=(bas-sum+(LL)n*(LL)k-delt-1)/((LL)n*(LL)k-delt); if(l+res>r) return ee; return (l+res)*n+p+1;
}
void solve(void){
	for(ll i=0,xz,yz,xt,yt;i<n;i++){
		if(val[i+1]!=ee) continue; xz=-1,yz=-1;
		if(sx[n]) xz=max((xg-sx[i+1])/sx[n],0ll); if(sy[n]) yz=max((yg-sy[i+1])/sy[n],0ll);
		if(xz>yz){
			val[i+1]=checkseg(0,yz,i,(sx[n]>0?-1:1),(sy[n]>0?-1:1)); if(val[i+1]!=ee) continue;
			val[i+1]=checkseg(yz+1,xz,i,(sx[n]>0?-1:1),(sy[n]>0?1:-1)); if(val[i+1]!=ee) continue;
			val[i+1]=checkseg(xz+1,ee,i,(sx[n]>0?1:-1),(sy[n]>0?1:-1));
		}else{
			val[i+1]=checkseg(0,xz,i,(sx[n]>0?-1:1),(sy[n]>0?-1:1)); if(val[i+1]!=ee) continue;
			val[i+1]=checkseg(xz+1,yz,i,(sx[n]>0?1:-1),(sy[n]>0?-1:1)); if(val[i+1]!=ee) continue;
			val[i+1]=checkseg(yz+1,ee,i,(sx[n]>0?1:-1),(sy[n]>0?1:-1));
		}
	}
}
int main(void){
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	ll Tccs=1;
	cin>>Tccs;
	for(ll tcs=1;tcs<=Tccs;tcs++){
		cin>>n>>k>>xg>>yg; ans=ee;
		for(int i=1;i<=n;i++) cin>>X[i]>>Y[i],sx[i]=sx[i-1]+X[i],sy[i]=sy[i-1]+Y[i],val[i]=ee;
		if(xg==0&&yg==0){cout<<"0\n"; continue;}
		else solve();
		for(int i=1;i<=n;i++) ans=min(ans,val[i]);
		cout<<(ans>=ee?-1:ans)<<"\n";
	}
	return 0;
}
posted @ 2024-03-16 18:21  aeiouaoeiu  阅读(19)  评论(0)    收藏  举报