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

这辈子不会想写第二次的题目

题目链接

解题思路

实际上就是推式子,再加上一个常见的trick

问题转换

定义:固定位移为题目中的x,y,调整位移为题目中的x',y',那么结果就是Σ固定位移 + Σ调整位移 = x,y

问题可以变为以下这样

  1. $ \sum_{i=0}^{m-1}(x_{i mod n}) + \sum_{i=0}^{m-1}({x'}_i) = X $
  2. $ \sum_{i=0}^{m-1}(y_{i mod n}) + \sum_{i=0}^{m-1}({y'}_i) = Y $
  3. $ |\sum_{i=0}^{m-1}({x}i)| + |\sum^{m-1}({y'}_i)| \le mk $

转换1,2,可以得到:

4.$\sum_{i=0}^{m-1}({x'}i) = X - \sum^{m-1}(x_{i mod n}) $

5.$ \sum_{i=0}^{m-1}({y'}i) = Y - \sum^{m-1}(y_{i mod n}) $

4 + 5 带入 3,可以得到

$ |X - \sum_{i=0}^{m-1}(x_{i mod n})| + |Y - \sum_{i=0}^{m-1}(y_{i mod n})| \le mk$

好了,此时第一步完成了

拆绝对值

接下来先给出一个常见trick:

$ | a - b | \le x\(,就是要\) a - b \le x$ 且 $ b - a \le x$

那么$ |X - \sum_{i=0}^{m-1}(x_{i mod n})| + |Y - \sum_{i=0}^{m-1}(y_{i mod n})| \le mk$就可以转变成以下四个条件同时满足

  • $ X - \sum_{i=0}^{m-1}(x_{i mod n}) + Y - \sum_{i=0}^{m-1}(y_{i mod n}) \le mk$
  • $ X - \sum_{i=0}^{m-1}(x_{i mod n}) - Y + \sum_{i=0}^{m-1}(y_{i mod n}) \le mk$
  • $ -X + \sum_{i=0}^{m-1}(x_{i mod n}) + Y - \sum_{i=0}^{m-1}(y_{i mod n}) \le mk$
  • $ -X + \sum_{i=0}^{m-1}(x_{i mod n}) - Y + \sum_{i=0}^{m-1}(y_{i mod n}) \le mk$

然后再转化一下,就可以变成:

  • [\sum_{i=1}^m(x_i+y_i+k)\geq X+Y]

  • [\sum_{i=1}^m(x_i-y_i+k)\geq X-Y]

  • [\sum_{i=1}^m(-x_i+y_i+k)\geq -X+Y]

  • \(\sum_{i=1}^m(-x_i-y_i+k)\geq -X-Y\)

(这里已经把x,y给无限循环了,也从1~n了,这样可以和写代码一样,不然太痛苦了)

接下来是初中数学:

以这个式子进行分析:\(\sum_{i=1}^m(x_i+y_i+k)\geq X+Y\)

显然,\(m = Kn + b\)

定义$ S = $ \(\sum_{i=1}^n(x_i+y_i+k)\),$ pos = \sum_{i=1}^b(x_i+y_i+k)$

那么问题就变成解不等式\(SK + pos \le mk\),可以解得\(K\)的大小

对于\(b\),枚举\(n\)就行了,注意\(S\)可能等于\(0\)

代码实现

看似简单,实则要自己手写向上/向下取整,调了2h

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
int n;
LL k;
LL X,Y;
const int N = 1e5 + 10;
LL x[N],y[N];
int test_id = 0;
LL s1,s2,s3,s4;
LL pos1,pos2,pos3,pos4;
const LL inf = 1e18;
LL my_ceil(LL a,LL b){
	if(a > 0 && b > 0) return a / b + (a % b != 0);
	return a / b;
}
LL my_floor(LL a,LL b){
	if(a > 0 && b < 0) return -1;
	if(a / b < 0 && (a % b != 0)) return a / b - 1;
	return a / b;
}
pair< LL , LL > calc(LL k, LL b, LL t){
	if(k < 0){
		return {0,my_floor(t-b,k)};
	}
	if(k == 0){
		if(b >= t)
			return {0,inf};
		if(b < t)
			return {inf+1,-1};
	}
	if(k > 0){
		return {my_ceil(t-b,k),inf};
	}
	return {114,514};
}
pair<LL,LL> get(pair<LL,LL> x,pair<LL,LL> y){
	return {max(x.fi,y.fi),min(x.se,y.se)};
}
void solve(){
	test_id  ++ ;
	cin >> n >> k >> X >> Y;
	s1 = s2 = s3 = s4 = 0;
	pos1 = pos2 = pos3 = pos4 = 0;
	for(int i=1;i<=n;i++) cin >> x[i] >> y[i];
	for(int i=1;i<=n;i++){
		s1 += k - x[i] - y[i];
		s2 += k - x[i] + y[i];
		s3 += k + x[i] - y[i];
		s4 += k + x[i] + y[i];
	}
	LL ans = inf + 1;
	for(int i=0;i<n;i++){
		pair<LL ,LL>  ran = {0,inf};
		if(i > 0){
			pos1 += k - x[i] - y[i];
			pos2 += k - x[i] + y[i];
			pos3 += k + x[i] - y[i];
			pos4 += k + x[i] + y[i];
		}
		ran = get(ran,calc(s1,pos1,-X - Y));
		ran = get(ran,calc(s2,pos2,-X + Y));
		ran = get(ran,calc(s3,pos3,X - Y));
		ran = get(ran,calc(s4,pos4,X + Y));
		if(ran.fi <= ran.se){
			ans = min(ans,ran.fi * n + i);
		}
	}
	if(ans == inf + 1) ans = -1;
	cout << ans << "\n";
}
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T -- ) solve();
	return 0;
}
posted @ 2025-12-19 21:53  WinterXorSnow  阅读(0)  评论(0)    收藏  举报