*题解:[ABC467E] Adjacent Sums (hard)

题目链接

解析

不难发现,只要确定某个 \(A_i\),那么其它的 \(A_j\) 也能唯一确定。不妨尝试确定 \(A_1\),考虑 \(A_1 \leftarrow A_1 + 1\) 对答案带来的影响。记 \(A'_i\) 表示不对 \(A_1\) 进行操作,为使得序列合法,在模 \(M\) 意义下\(A_i\) 需要达到的值,也就是说 \(A'_i = B_{i - 1} - A'_{i - 1}\)。每当 \(A'_1 \leftarrow A'_1 + 1\),由于需要有 \(A'_1 + A'_2 \equiv B_1\),因此需要令 \(A'_2 \leftarrow A'_2 - 1\);由于需要有 \(A'_2 + A'_3 \equiv B_2\),因此需要令 \(A'_3\leftarrow A'_3 + 1\)。依此类推,规律是奇数位置 \(+1\),偶数位置 \(-1\)

答案即为:

\[\sum_{i=1}^n ((A'_i - (-1)^ ix - A_i) \bmod M) \]

其中 \(x=A'_1 - A_1\)。对于每次 \(A'_1 \leftarrow A'_1 + 1\)\(x' \leftarrow x + 1\) 的操作,奇数位置 \(i\) 上的值变为 \((A'_i+x-A_i + 1) \bmod M\),此次操作所做的贡献当 \((A'_i + x' - A_i) \equiv 0\) 时为 \(-M\),其余情况时为 \(1\)。偶数位置上同理,当 \((A'_i - x' - A_i) \equiv M-1\) 时,做的贡献为 \(M\),其余情况为 \(-1\)。由于奇数位置个数不少于偶数位置个数,所以通常情况下 \(x \leftarrow x + 1\) 会使得答案 \(+1\) 或者不变,在一些情况下可能会使得答案减少(如上文所描述的奇数位置上的特殊贡献),故只需统计使得某个 \(i\) 满足 \((A'_i + x - A_i) \equiv 0\)\(2 \nmid i\) 的所有 \(x\) 对应的答案。

为了统计,我们还要对偶数位置求满足 \((A'_i - x' - A_i) \equiv M-1\)\(x\) 以处理这些位置上的特殊贡献。

实现上,需要 \(O(n)\) 求出所有 \(x\),将其排序并依次统计。时间复杂度 \(O(n \log n)\)

代码

/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 2e5 + 5, M = 200000 + 5, P = 450, mod = 1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
int a[N],b[N],a1[N];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
//	freopen("in.txt","r",stdin);
// 	freopen("out.txt","w",stdout);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<n;i++){
		cin>>b[i];
	}
	ll cnt = 0,res = 9e18;
	a1[1] = a[1];
	for(int i=2;i<=n;i++){
		a1[i] = ((b[i - 1] - a1[i - 1]) % m + m) % m;
		cnt += ((a1[i] - a[i]) % m + m) % m;
	}
	vector<pii> v;
	for(int i=1;i<=n;i++){
		int x;
		if(i & 1){
			x = ((a[i] - a1[i]) % m + m) % m;
		}else{
			x = ((a1[i] - a[i] + 1) % m + m) % m;
		}
		if(!x) x += m;//特殊贡献对应的 x 必须有前驱
		v.push_back({x,i % 2 == 0 ? m : - m});
	}
	sort(v.begin(),v.end());
	int l = 0,r = 0,last = 0;
	while(r < v.size()){
		while(r < v.size() && v[l].first == v[r].first){
			cnt += v[r].second;
			r++;
		} 
		cnt += (v[l].first - last) * (n % 2 != 0);
		res = min(cnt,res);
		last = v[l].first;
		l = r;
	}
	cout<<res;
    return 0;
}
posted @ 2026-07-23 18:52  yutar  阅读(6)  评论(0)    收藏  举报