开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
A - Modulo Ruins the Legend
Grammy has a sequence of integers . She thinks that the elements in the sequence are too large, so she decided to add an arithmetic progression to the sequence. Formally, she can choose two non-negative integers , and add to for each .
Since we want to ruin the legend, please tell her the minimum sum of elements modulo after the operation. Note that you should minimize the sum after taking the modulo.
中文大意
给我们一个数组数组中的每个数都不大于m,现在我们要给每个数加上s + kd,k是这个数组的下标,s和d是我们选择的非负数并且不能大于m,问经历过上面的操作过后整个数组的和对m取模最小值是多少
解法
通过题意我们很容易看出这个是一个等差数列所以我们直接运用等差数列的求和公式,然后我们现在就可以得到一个这样的式子现在我们要求得就是这个式子对m取模得最小值 我们发现这个式子和拓展欧几里得得式子很像所以我们就用拓展欧几里得来处理这个式子 这个式子得最优解肯定是为0得时候所有现在式子成了这个样子
对于这个式子得处理我们先把变成x*gcd(a,b)他的一个通解就是s,t
现在式子又成了这个样子这又是一个exgcd的公式这时的c就是我们的最小值这样我们就能求出一个答案的最小解了
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int c[N];
ll exgcd(ll a, ll b,ll &x, ll &y) {
if(b == 0) {
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a%b, y, x);
y -= a/b * x;
return d;
}
void solve() {
ll n, m; scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", c + i);
ll s = 0, d = 0;
ll a = n, b = n * (n + 1) / 2;
ll num = 0;
for(int i = 1; i <= n; i++) num += c[i];
num %= m;
ll res = exgcd(a, b, s, d);
ll ans = num % __gcd(res, m);
printf("%lld\n", ans);
ll x = 0, y = 0;
ll k = exgcd(m, res, y, x);
ll p = x % m * (ans - num) / k % m;
p = (p % m + m) % m;
s *= p, d *= p;
printf("%lld %lld\n", (s % m + m) % m, (d % m + m) % m);
}
int main() {
int T = 1;
// scanf("%d", &T);
while(T--) solve();
}