D.石子游戏
题目链接:https://ac.nowcoder.com/acm/contest/9985/D
题目描述:
叶妹妹很喜欢玩石头,于是这天泽鸽鸽给她出了一道石子游戏,规则是这样的:有n堆石子排成一行,其中第i堆石子有ai个,叶妹妹可以选择做无数次这种操作:每次操作把连续相邻的k个石子堆中的每堆石子数目加一,请问叶妹妹能否让每堆石子的数目都相同呢?叶妹妹觉得这题太简单了,于是丢给了聪明的你,快来解决这个问题吧!
输入描述:
第一行输入样例组数T
对于每组样例来说,第一行输入两个数n和k
第二行输入n个数,其中第i个数为ai
【数据规模与约定】
1≤T≤10,1≤n≤10^5 ,1≤k≤n,0≤ai≤10^9
输出描述:
输出总共T行,对于每组样例来说,如果能使每堆石子的数目都相同则输出一个整数x,x表示达到相同时的最少的操作数;否则输出-1
示例1:
输入
1
4 3
1 1 1 2
输出
1
解题思路:
差分
从后向前进行操作,如果找到了任意的x>0,则用x次操作变为0。对于本题来说,给一个后缀+1,(第n+1-k个位置+1)会受到影响,(也就是n+1%k同余位置),因此需要把这些位置的负数置0。
代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,k,a[100010]={
0};
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=n;i>=1;i--){
a[i]-=a[i-1]; //求差分数组
}
ll ans=0;
for(int i=n;i>=2;i--)
if(i>k&&a[i]>0)
ans+=a[i],a[i-k]+=a[i],a[i]=0;
int t=1;
for(int i=2;i<=n;i++){
if(a[i]<0&&(i%k==(n+1)%k))
ans-=(n+1-i)/k*(ll)a[i],a[i]=0; //特判
t&=!a[i];
}
if(!t) ans=-1;
printf("%lld\n",ans);
}
return 0;
}