一排,有
n
n
n 个石头堆,第
i
i
i 堆有
a
i
a_i
ai 个石头。 给你一个
k
k
k 。 你每次可以选择相邻的
k
k
k 个石头堆,进行一次操作,这
k
k
k 堆,每堆石头个数都会增加
1
1
1 问你最少操作个数使得每堆石头个数都相同,或者输出
−
1
-1
−1 表示不可能。
【范围】
样例组数
T
≤
10
T\le 10
T≤10
1
≤
k
≤
n
≤
1
0
5
1\le k\le n\le 10^5
1≤k≤n≤105
0
≤
a
i
≤
1
0
9
0\le a_i\le 10^9
0≤ai≤109
【思路】赛内
我感觉不是直接二分+贪心就能做好的,因为假设最后每堆石头个数都是
x
x
x 可能
x
x
x 是可以达成的,但是
x
−
1
x-1
x−1 与
x
+
1
x+1
x+1 都是无法达成的,比较棘手。 于是我就对
x
x
x 进行了分析: 例子:
n
=
5
,
k
=
3
,
a
[
]
=
{
5
,
2
,
1
,
3
,
7
}
n=5,k=3,a[\ ]=\{ 5\ ,2\ ,1\ ,3\ ,7\}
n=5,k=3,a[]={5,2,1,3,7} 我们已经假设最终每堆都有
x
x
x 个石头了,那么由于第一堆增加到
x
x
x 的方案只有一种,就是选择增加
1
,
2
,
3
1,2,3
1,2,3 堆,每堆增加
x
−
5
x-5
x−5 个,于是变成了:
a
[
]
=
{
x
,
x
−
3
,
x
−
4
,
3
,
7
}
a[\ ]=\{ x\ ,x-3\ ,x-4\ ,3\ ,7\}
a[]={x,x−3,x−4,3,7} 重复下去。第二堆石头需要增加
3
3
3 个,增加方案也只有一种,就是
2
,
3
,
4
2,3,4
2,3,4 堆每堆增加
3
3
3 个。 我们从头到尾来一遍:
a
[
]
=
{
5
,
2
,
1
,
3
,
7
}
a
[
]
=
{
x
,
x
−
3
,
x
−
4
,
3
,
7
}
a
[
]
=
{
x
,
x
,
x
−
1
,
6
,
7
}
a
[
]
=
{
x
,
x
,
x
,
7
,
7
}
\begin{matrix} a[\ ]&=\{&5\ ,&2\ ,&1\ ,&3\ ,&7\}\\ a[\ ]&=\{&x\ ,&x-3\ ,&x-4\ ,&3\ ,&7\}\\ a[\ ]&=\{&x\ ,&x\ ,&x-1\ ,&6\ ,&7\}\\ a[\ ]&=\{&x\ ,&x\ ,&x\ ,&7\ ,&7\}\\ \end{matrix}
a[]a[]a[]a[]={={={={5,x,x,x,2,x−3,x,x,1,x−4,x−1,x,3,3,6,7,7}7}7}7} 可以看到,有解的情况就是
x
=
7
x=7
x=7,即剩下下标从
n
−
k
+
2
∼
n
n-k+2\sim n
n−k+2∼n 的所有数字都相同。 当然还有一些特殊情况,比如:
n
=
3
,
k
=
3
,
a
[
]
=
{
1
,
1
,
1
}
n=3,k=3,a[\ ]=\{1,1,1\}
n=3,k=3,a[]={1,1,1} 这样我们操作完之后,
a
[
]
=
{
x
,
x
,
x
}
a[\ ]=\{x,x,x\}
a[]={x,x,x}。这个时候,我们的解就是原来序列的元素的最大值。 我们得到了
x
x
x 之后,就能知道增加了多少个石头,然后每次操作是增加
k
k
k 个,做个除法就行。
那么问题来了,我们代码里面怎么去设自变量
x
x
x? 额,随便给一个大的常量就行了。 给小常量是不行的,因为这样比如可能导致上面例子中的
5
>
x
5>x
5>x ,然后差分增加数字会比较麻烦。
我怎么知道当前位置为
x
x
x 还是某个数字增加了一些值后的新值? 可以看到,一定是每
k
k
k 个数字一起变成
x
x
x 的,我们记录一下
l
a
s
t
last
last 表示第一位非
x
x
x 的位置即可。
【代码】
时间复杂度:
O
(
T
×
n
)
O(T\times n)
O(T×n) 记得用差分处理区间增加
91
/
1000
M
s
91/1000Ms
91/1000Ms
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/constint MAX =1e5+50;
ll aa[MAX];
ll de[MAX];
ll aim =(ll)2e9;intmain(){int T;scanf("%d",&T);while(T--){
ll mx =0;int n,k;scanf("%d%d",&n,&k);for(int i =0;i <= n +1;++i)de[i]=0;for(int i =1;i <= n;++i){scanf("%lld",&aa[i]);
mx =max(mx,aa[i]);}
bool can = true;
ll now =0;int last =0;for(int i =1;i + k -1<= n;++i){// 算前面的区间都要变成 aim
now += de[i];
ll shu = aa[i]+ now;if(shu > aim){
can = false;break;}elseif(shu < aim){
de[i+1]+= aim - shu;
de[i+k]-= aim - shu;if(i > last)
last = i + k -1;}}
ll ans =-1;if(last){for(int i = n - k +2;i <= last;++i){// 这些数字必须都是 aim
now += de[i];
ll shu = aa[i]+ now;if(shu != aim){
can = false;break;}}for(int i = last +1;i <= n;++i){// 这些都是常数,常数都要相同
now += de[i];
ll shu = aa[i]+ now;if(ans ==-1)ans = shu;elseif(ans != shu){
can = false;break;}}}if(!can)puts("-1");else{if(ans ==-1)ans = mx;
ll cha =0;for(int i =1;i <= n;++i){
cha += ans - aa[i];}
cha /= k;printf("%lld\n",cha);}}return0;}