ARC182D Increment Decrement Again
Solution
很好的 Ad-hoc!
首先发现这个取模非常难处理,那么不妨考虑先不取模,做完操作后再取模。那么限制相当于要求 \(|a'_i - a'_{i + 1}| < m\),且 \(a'_{i},a'_{i + 1}\) 两者的大小关系不变。这些显然是必要条件,同时我们断言,这些就是序列合法的充要条件。构造出一个合法的方案也很简单:首先不妨令 \(a_{i} < a_{i + 1}\),于是假设 \(a'_{i} < a'_{i + 1}\) 向下一步一步调整即可,反之将 \(a'_{i + 1}\) 向上调整,然后这样就会跳到最下面,由于两个东西的差 \(< m\),因此不会跨过 \(a'_i\) 相同的模数。但是在 \(m = 2\) 时向上和向下是一样的,因此不能调整,需要特判。
于是我们可以先令 \(a'_1 = b_1\) ,根据上面的规则构造出一个合法的序列且与 \(b\) 同构。然后考虑操作次数,我们可以对 \(b\) 数组进行整体平移 \(km\)(\(k\) 是整数)。那么操作次数就是 \(\sum_{i = 1}^n{|a_i - (a'_i + km)|}\)。令 \(c_i = a_i - a'_i\),根据小学知识,\(km\) 取到 \(c\) 的中位数两侧最优,直接算出来即可(没看懂 Wa90 的题解中为什么要二分)。
Code:
qwq
#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, m, a[N], b[N], c[N];
ll solve(ll x){
ll ans = 0;
for(int i = 1; i <= n; i++) ans += abs(c[i] - x);
return ans;
}
int fl(int x, int y){
if(x >= 0) return (x / y);
else{
if(x % y) return (x / y - 1);
else return (x / y);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
if(m == 2){
for(int i = 1; i <= n; i++) if(a[i] != b[i]){cout << -1; return 0;}
cout << 0; return 0;
}
c[1] = b[1];
for(int i = 2; i <= n; i++){
int val = (b[i] - b[i - 1] + m) % m;
if(a[i] > a[i - 1]) c[i] = c[i - 1] + val;
else c[i] = c[i - 1] + val - m;
}
for(int i = 1; i <= n; i++) c[i] = a[i] - c[i];
sort(c + 1, c + n + 1); ll p = c[(n + 1) / 2];
cout << min(solve(fl(p, m) * m), solve((fl(p, m) + 1) * m));
return 0;
}

浙公网安备 33010602011771号