题目大意
给你一个长度为n的序列A,每次选择一段区间,在模m的意义下整体+1或-1,问最少需要多少次操作才能使序列A变为0
思路
看到对于区间整体加减,应当要想到差分
我们设
a
0
=
a
n
+
1
=
0
a_0=a_{n+1}=0
a0=an+1=0,
b
i
=
a
i
−
a
i
−
1
b_i=a_i-a_{i-1}
bi=ai−ai−1
(
m
o
d
m
)
(mod \ m)
(mod m)
(
0
≤
i
≤
n
+
1
)
(0\le i \le n+1)
(0≤i≤n+1)
设
a
0
=
a
n
+
1
=
0
a_0=a_{n+1}=0
a0=an+1=0 就可以保证当
∀
b
i
=
0
\forall b_i=0
∀bi=0 时,
∀
a
i
=
0
\forall a_i=0
∀ai=0
由于差分的性质,每一个操作其实就是
b
l
+
1
或
−
1
b_l+1或-1
bl+1或−1 ,
b
r
+
1
−
1
或
+
1
b_{r+1}-1或+1
br+1−1或+1
因为题目允许你+1或-1,所以就没有任何顺序的要求了
故我们可以将数组
b
b
b 从小到大排个序,接着我们枚举一个分界点,从这个分界点之前的都-1,以后的都+1,由于加一和减一是成对存在的,那么说我们就必须要求减1的个数要等于加1的个数,用前后缀和处理一下就可以了
Code
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+5;
int n;
ll a[N],s[N],b[N],m;
int main(){
freopen("lock.in","r",stdin);
freopen("lock.out","w",stdout);
scanf("%d%lld",&n,&m);
for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
for (int i=1;i<=n+1;++i) b[i]=(a[i]-a[i-1]+m)%m;
sort(b+1,b+1+n+1);
for (int i=1;i<=n+1;++i) s[i]=s[i-1]+b[i];
ll sum=0;
for (int i=n+1;i>=1;--i){
sum=sum+m-b[i];
if (s[i-1]==sum){
printf("%lld\n",s[i-1]);
break;
}
}
return 0;
}