P10217 [省选联考 2024] 季风 题解

本文最后更新于 2026年2月21日 下午

-1 前言

神人题目。

记得当时是2024年3月3日下午,当时机房里面几个大佬去了省选~~,虽然当时我没有去省选~~,但是这题出在luogu的第一时间我就开始做这题。想了非常长时间,各种结论非常混乱,最后还没能做出来。接近两年之后的省选前夕竟然又看到了这题,两年过去水平应该是有了巨大的变化,但是相同的是依旧没有去省选的资格/ll。

既然说季风和题意还有做法有关系,那么接下来我将严肃思考我常常追忆过去和 bitset 的联系。

0 芝士

  • 神秘的数学

1 题意

为避免混淆,下文使用 X,YX,Y 代替原文中给定数值 x,yx,y,并且区别于题目的是,下文序列全部为1-index,这并不会影响做题。

题面非常形式化。

但是这个题真的和季风有关系的,把 (x,y)(x,y) 看成目标点,(xi,yi)(x'_i,y'_i) 看成自主移动,kk 为限制,(xi,yi)(x_i,y_i) 看成季风扰动,问题就是求要移动到目标点的最小步数。如果题面这么写应该会更好看也会更好理解些。

这么说我的追忆旅程疑似是一张DAG。

2 思路

下文参考了Luogu题解区第1,3篇题解,在此感谢。

首先还是,因为有题目里面有这种循环的 xxyy,所以考虑先把这两个当作无限循环的序列。

先来转化一下题目里面的性质。容易发现我们不关心具体的 xx'yy' 序列,所以对于每一条的具体限制 xi+yik|x'_i|+|y'_i|\le k 并不重要,只要总体上不超限制就一定可以调整出一组合法的 xix'_iyiy'_i 来。所以有以下式子:

mxi+myimk=mxiX+myiYmk\sum^{m} |x'_i|+\sum^{m} |y'_i| \le m\cdot k\\ = |\sum^{m} x_i-X|+|\sum^{m} y_i-Y| \le m\cdot k\\

这个对的原因是我们一定可以让 xx'yy' 整个序列的正负相同,因为序列中同时出现正数和负数肯定可以相加抵消成一个数。

然后是经典的思路之差绝对值:

m(xi+yik)X+Ym(xi+yik)X+Ym(xiyik)XYm(xiyik)XY\sum^m (x_i+y_i-k) \le X+Y\\ \sum^m (-x_i+y_i-k) \le -X+Y\\ \sum^m (x_i-y_i-k) \le X-Y\\ \sum^m (-x_i-y_i-k) \le -X-Y

上面的移一下项就是很好推的。为了下面代码实现方便再给上面四个全都两边取反:

m(xi+yi+k)X+Ym(xi+yi+k)X+Ym(xiyi+k)XYm(xiyi+k)XY\sum^m (x_i+y_i+k) \ge X+Y\\ \sum^m (-x_i+y_i+k) \ge -X+Y\\ \sum^m (x_i-y_i+k) \ge X-Y\\ \sum^m (-x_i-y_i+k) \ge -X-Y

可以发现,上面这四个同时满足的 mm 才是合法的 mm

这四个式子只有 x,yx,yX,YX,Y 的符号有点小差别,因此我们先用第一个来推一推式子,其余的类似。

考虑由于 x,yx,y 是无限循环的,所以令 m=hn+bm=hn+b。同时令 prej=i=1j(xi+yi+k)pre_j=\sum_{i=1}^{j}(x_i+y_i+k)。则式子可以表示为:

hpren+prebX+Yh\cdot pre_n + pre_b \ge X+Y

显然这个时候 bb 是可以枚举的,于是考虑枚举 bb,求出对应 hh 的区间:

  • pren=0pre_n=0,则当且仅当 prebX+Ypre_b\ge X+Y 时解为全非负整数,否则解集为空。

  • pren>0pre_n>0,那么

    hX+Yprebprenh \ge \lceil \frac{X+Y-pre_b}{pre_n}\rceil

    并且要注意 hh 也是非负整数,即上式要满足 X+YprebX+Y\ge pre_b,否则解集为 h0h\ge 0

  • pren<0pre_n< 0,那么和上文类似的:

    hX+Yprebprenh \le \lfloor \frac{X+Y-pre_b}{pre_n}\rfloor

    同样的,上式要满足 X+YprebX+Y\le pre_b,否则解集为空。

枚举完 bb 我们就得到了 nn 个解集。对其他三个式子做一遍类似的过程,得到对应 bb 的解集取交,得到每个 bb 的最终解集 [li,ri][l_i,r_i]。然后再次枚举一遍 bb 算答案,也就是 ansminb=1n{lin+b}ans\leftarrow\min_{b=1}^{n}\{l_i\cdot n+b\},就做完了。

细节好像也没什么细节,就是要记得特判一下 X=Y=0X=Y=0 的情况,否则过不去样例

3 代码

需要注意多测清空和向上取整。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int n,k,x,y,a[N],b[N],pre[N],l[N],r[N];
void solve(int fx,int fy){
for(int i=1;i<=n;++i){pre[i]=pre[i-1]+fx*a[i]+fy*b[i]+k;}
int xx=fx*x,yy=fy*y;
if(pre[n]==0){
for(int i=1;i<=n;++i){if(pre[i]<xx+yy)r[i]=ivl;}
return;
}
for(int i=1;i<=n;++i){
if(pre[n]>0){
if(pre[i]<=xx+yy)l[i]=std::max(l[i],(xx+yy-pre[i])/pre[n]+((xx+yy-pre[i])%pre[n]?1:0));
else l[i]=;
}else{
if(pre[i]<xx+yy)r[i]=ivl;
else r[i]=std::min(r[i],(xx+yy-pre[i])/pre[n]);
}
}
}
signed main(){
int T=read();
while(T--){
r[0]=ivl;
n=read(),k=read(),x=read(),y=read();
for(int i=1;i<=n;++i){
l[i]=0;r[i]=inf;
}
for(int i=1;i<=n;++i){a[i]=read(),b[i]=read();}
if(!x&&!y){printf("0\n");continue;}
solve(1,1);
solve(1,-1);
solve(-1,1);
solve(-1,-1);
int ans=inf;
for(int i=1;i<=n;++i){
if(l[i]<=r[i]){
ans=std::min(ans,i+l[i]*n);
}
}
if(ans==inf)printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}

4 时间复杂度分析

没啥好分析的,简单 O(n)O(n)

5 后记

神人题目。

生日愿望是能去 WC2027。我有生之年一定要在WC的舞台上唱白鸟过河滩!!!!1


P10217 [省选联考 2024] 季风 题解
http://ljhljh1102,github.io/2026/02/19/P10217-省选联考-2024-季风-题解/
作者
1102
发布于
2026年2月19日
许可协议