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;
}
posted @ 2025-02-20 19:37  Little_corn  阅读(16)  评论(0)    收藏  举报