石子游戏(思维+差分)

16 篇文章 0 订阅

https://ac.nowcoder.com/acm/contest/9985/D


题意:

叶妹妹很喜欢玩石头,于是这天泽鸽鸽给她出了一道石子游戏,规则是这样的:有n堆石子排成一行,其中第i堆石子有ai​个,叶妹妹可以选择做无数次这种操作:每次操作把连续相邻的k个石子堆中的每堆石子数目加一,请问叶妹妹能否让每堆石子的数目都相同呢?叶妹妹觉得这题太简单了,于是丢给了聪明的你,快来解决这个问题吧!

思路:

一眼的差分题阿。但是边界搞糊涂了。再理解理解。

差分就是表示每个数之间的差。那么对于此题就是要求我们使得cnt[i]=a[i+1]-a[i],也就是使得n-1个差分数组都为0.

只要都为0就可以了,所以cnt[n]和cnt[0]是多少无所谓,而cnt[n]和cnt[0]是多少其实影响的是最后序列里的每个数是多少,不影响相等不相等。

于是前往后扫一遍,由于是区间+1,所以只对cnt[i]<0的进行操作。注意边界是i+k>n,而不是=n,因为最后一个数cnt[n]和cnt[0]是无所谓的。

然后后往前扫一遍,此时是反过来的。cnt[i]>0的话说明后面的大,要给前面的数都加,于是cnt[i-k]+=abs(cnt[i])

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL a[maxn],cnt[maxn];
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
    LL n,k;cin>>n>>k;
    for(LL i=1;i<=n;i++) cin>>a[i],cnt[i]=0,cnt[0]=cnt[n+1]=0;
    for(LL i=1;i<n;i++){
        cnt[i]=(a[i+1]-a[i]);
    }
    LL ans=0;
    for(LL i=1;i<n;i++){
        if(cnt[i]<0){
            if(i+k>n) continue;
            cnt[i+k]-=abs(cnt[i]);
            ans+=abs(cnt[i]);
            cnt[i]=0;
        }
    }
    for(LL i=n-1;i>=1;i--){
        if(cnt[i]>0){
            if(i-k<0) continue;
            cnt[i-k]+=abs(cnt[i]);
            ans+=abs(cnt[i]);
            cnt[i]=0;
        }
    }
    bool flag=1;
    for(LL i=1;i<n;i++){
        if(cnt[i]!=0){
            cout<<"-1"<<"\n";
            flag=0;break;
        }
    }
    if(1==flag){
        cout<<ans<<"\n";
    }
  }
return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值