大致题意 已知一个数组 选择两个非负整数s,d 对数组的每一项a[k]进行s+kd的操作 k∈[1,n]
求取模m后的最小和及s和d
不难看出 最后的和为原数组的和(设为sum)加上一个首项为s+d公差为d的等差数列 由此我们
可以列出 (1) sum+n*s+n*(n+1)/2*d=ans-k1*m (设ans为最后的和 ans-k1*m表示ans%m后的值)
若想要s和d有解 那么n*s+n*(n+1)/2*d=k2*gcd(n,n*(n+1)/2)必定成立 我们设gcd(n,n*(n+1)/2)=g
带入(1)式可以得出sum+k2*g=ans-k1*m 随意整理一下得出 (2)k2*g+k1*m=ans-sum 若有解 那么
k2*g+k1*m=k3*gcd(g,m) 也必定成立 因此得出k3*gcd(g,m)=ans-sum 因此ans+k3*gcd(g,m)=sum 那么 不难看出 ans=sum%gcd(g,m) ans求出后 可带入(2)式求出
k2 再带入n*s+n*(n+1)/2*d=k2*gcd(n,n*(n+1)/2) 可求出s和d
AC代码附
//
// Created by 李秉龙 on 2023/8/10.
//
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
#define ll long long
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll g=exgcd(b,a%b,x,y);
ll temp=x;
x=y;
y=temp-(a/b)*y;
return g;
}
ll gcd(ll a,ll b){
if(b==0) return a;
return gcd(b,a%b);
}
int main()
{
ll n,m;scanf("%lld %lld",&n,&m);
ll sum=0;
for(int i=0;i<n;i++){
ll t;scanf("%lld",&t);
sum=sum+t;
}
sum%=m;
ll s,d;
ll g= exgcd(n%m,n*(n+1)/2%m,s,d);
s%=m;d%=m;
ll k1,k2;
ll g1= exgcd(g,m,k2,k1);
ll ans=sum%g1;ll k3=(ans-sum)/g1;
k2=k2*k3%m;
s=(s*k2%m+m)%m;
d=(d*k2%m+m)%m;
cout<<ans<<endl;
cout<<s<<" "<<d<<endl;
}