[省选联考 2024] 季风 题解

首先整理式子,把 xixi 分开。

  • i=0m1xi=xi=0m1ximodn
  • i=0m1yi=yi=0m1yimodn

看到 |xi|+|yi|k,我们不妨将 xy 放到一起考虑。

  • i=0m1(xi+yi)=xi=0m1ximodn+yi=0m1yimodn

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

例如,当 xi=0m1ximodn<0,yi=0m1yimodn>0 时,两者加在一起反倒会让目标距离更短,不一定合法。

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

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

  • mk|xi=0m1ximodn|+|yi=0m1yimodn|

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

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

  • (qn+p)k|xsxpqsxn1|+|ysypqsyn1|

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

不妨设 fx(q)=|xsxpqsxn1|,fy(q)=|ysypqsyn1| 的函数值为 0 时分别有 q=xz,yz

fx(q) 进行分讨:

  • 0qxz,此时 q 的增长给 fx(q) 带来了负收益。

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

fy(q) 同理。

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

我们需要实现一个函数 check(l,r,p,xd,yd) 能够求出在 lqrfx(q)fx(q1)=xdsxn1,fy(q)fy(q1)=ydsyn1 时,q 的最小值。

根据函数传入的参数,我们可以知道当 qq+1 时,fx(q)+fy(q) 的增/减量为 Δ=xdsxn1+ydsyn1

我们设 sum=(ln+p+1)k,bas=fx(l)+fy(l),R=ql。则我们要求一个不等式 sum+nkRbas+RΔ,最小的正整数解为 R=bassumnkΔ

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

时间复杂度:O(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 @   aeiouaoeiu  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示