P10217 [省选联考 2024] 季风题解
考场上没写出来,火大,实际上这题放校内%你赛我肯定写的出来,可惜这是省选。
实际上这题不难,主要是观察性质,接着拆柿子,然后就是有点难写,要写得好看有点考验代码构建能力和数学能力。
我们考虑原题的每对 \((x,y)\) 都要满足 \(|x|+|y|\le k\) 而我们可以知道后面应该填的 \((x,y)\) 如果超过了限制,那么可以将前面的 \((x,y)\) 变大来满足后面的需求,实际上就是因为考场上没有充分利用这个性质才没拆出来柿子。
那么我们现在开始推柿子。
\(|x^{'}_i|+|y^{'}_i|\le k\rightarrow \sum^{m-1}_{i=0}|x^{'}_{i}|+\sum^{m-1}_{i=0}|y^{'}_{i}|\le m\times k\)
\(\sum^{m-1}_{i=0}x^{'}_{i}=x-\sum^{m-1}_{i=0}x_{i}\)
\(y\) 同理。
那么可以推出:
\(|x-\sum^{m-1}_{i=0}x_{i \mod n} |+|y-\sum^{m-1}_{i=0}y_{i\mod n}|\le m\times k\)
绝对值里面的表示 \(x\) 或 \(y\) 的需求量,所以可以直接与 \(m\times k\) 比较。
看到 \(\mod n\) 就知道可以把这个拆开。
令 \(Sx_i,Sy_i\) 分别表示 \(x_i,y_i\) 的前 \(i\) 项和,\(m=t\times n +p\)。
\(|x-Sx_n\times t-Sx_p|+|y-Sy_n\times t-Sy_p|\le (t\times n +p)\times k\)
因为 \(p\in[0,n-1]\),所以可以直接枚举,那么就转化成了一个关于 \(t\) 的绝对值不等式,暴力拆成 \(4\) 种,再联立每种的条件不等式组成不等式组再找满足条件的最小值就可以开写了。
我们接着考虑优化代码结构。
上式可以统一形式为:
\(|c_1-k_1\times t|+|c_2-k_2\times t|\le k_3\times t+c_3\)
我们取直接去绝对值号产生的不等式为标准不等式。
\(c\le k\times t\)
其中 \(c=c_1+c_2-c_3,k=k_1+k_2+k_3\)。
而我们的条件不等式同样可以化为上面的形式,所以我们只要写一种解不等式方法再控制正负号就可以简化代码。
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define ll long long
#define ull unsigned long long
#define m_p make_pair
#define m_t make_tuple
#define inf (0x7f7f7f7f7f7f7f7f)
#define N 100010
using namespace std;
using namespace __gnu_pbds;
ll val1[N], val2[N], sumx[N], sumy[N], n, k, X, Y, T;
pair<bool, ll> calc(ll c, ll k) // true is upper,false is lower
{
if (!k)
return m_p(1, inf * (c <= 0 ? 1 : -1));
if (k < 0)
{
if (c > 0)
return m_p(1, -inf);
return m_p(1, c / k);
}
ll t = ceil(c * 1.0 / k * 1.0);
return m_p(0, max(t, 0ll));
}
ll solveine(ll c1, ll c2, ll c3, ll k1, ll k2, ll k3)
{
ll c = c1 + c2 - c3, k = k1 + k2 + k3, minx = inf, maxx = 0;
pair<bool, ll> t[5];
t[1] = calc(c, k);
t[2] = calc(-c1, -k1);
t[3] = calc(-c2, -k2);
for (int i = 1; i <= 3; i++)
if (t[i].first)
minx = min(minx, t[i].second);
else
maxx = max(maxx, t[i].second);
if (minx >= maxx)
return maxx;
else
return -1;
}
ll solve(ll k1, ll k2, ll k3)
{
ll c1, c2, c3, ans = -1, ans1;
for (ll i = 0; i < n; i++)
{
c1 = X - sumx[i];
c2 = Y - sumy[i];
c3 = (i + 1) * k;
ans1 = solveine(c1, c2, c3, k1, k2, k3);
if (ans1 != -1)
ans = (ans == -1) ? ans1 * n + i + 1 : min(ans, ans1 * n + i + 1);
ans1 = solveine(-c1, c2, c3, -k1, k2, k3);
if (ans1 != -1)
ans = (ans == -1) ? ans1 * n + i + 1 : min(ans, ans1 * n + i + 1);
ans1 = solveine(c1, -c2, c3, k1, -k2, k3);
if (ans1 != -1)
ans = (ans == -1) ? ans1 * n + i + 1 : min(ans, ans1 * n + i + 1);
ans1 = solveine(-c1, -c2, c3, -k1, -k2, k3);
if (ans1 != -1)
ans = (ans == -1) ? ans1 * n + i + 1 : min(ans, ans1 * n + i + 1);
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// int T;
cin >> T;
ll k1, k2, k3;
while (T--)
{
cin >> n >> k >> X >> Y;
for (int i = 0; i < n; i++)
cin >> val1[i] >> val2[i];
if (!X && !Y)
{
cout << "0\n";
continue;
}
sumx[0] = val1[0];
sumy[0] = val2[0];
for (int i = 1; i < n; i++)
{
sumx[i] = sumx[i - 1] + val1[i];
sumy[i] = sumy[i - 1] + val2[i];
}
k1 = sumx[n - 1];
k2 = sumy[n - 1];
k3 = n * k;
cout << solve(k1, k2, k3) << "\n";
}
return 0;
}
完事。