cdoj 1018 王之新学期

新的学期到来了,王早已经把整个学期全都安排好了。

整个学期一共 n 天,第 i 天安排了 Pi 件事情。可是就在开学的前一天晚上,王突然觉得这个整个学期安排可能不够有趣。

一个学期是有趣当且仅当对于任意一个整数 i(1in) ,第 i 天的的事情数目总是等于倒数第 i 天的事情数目。

因此王必须花费一定代价改变安排使得整个学期变得有趣。

王每次操作都花费一个代价,可以将一件事情从当天提前到昨天或者延后到明天。(第一天的事情不能提前,最后一天的事情不能延后)

请问王最小要花费多少的代价使得一个学期是有趣的?

比如,当 n=3,p1=2,p2=2,p3=0 时,

王可以先花费一个代价将第一天的一件事延后到第二天,就变成了 p1=1,p2=3,p3=0

再花费一个代价将第二天的一件事延后到第三天,就变成了 p1=1,p2=2,p3=1

显然, p1=1,p2=2,p3=1 是有趣的一个学期。花费的最小代价是 2

Input

一个整数 T ,表示数据组数。 T<1000

接下来 2×T 行。每组数据两行。

第一行一个整数 n ,表示盒子的个数。 (n<10000)

第二行 n 个整数,第 i 个整数 Pi 表示第 i 个天的最初的事件数。 (ai<10000)

Output

每组数据输出一个整数。表示王花费的最少代价。(如果王无论如何都不能达到目的,则输出-1

Sample input and output

Sample InputSample Output
3
2
0 1
3
1 3 2
5
1 0 0 0 0
-1
1
2

解析

贪心,从两边往中间堆。每次比较对称的两个点,取小的那个作为基准。多出来部分往中间堆。

从首尾两边往中间扫,先比较第一个和最后一个,把多出来的事移到第二个(正数或者倒数),直到扫到中间。再特殊处理n的奇偶情况就可以了。


#include<cstdio>

using namespace std;

#define LOCAL

typedef long long LL;

LL N,P[10010];

void readdata()
{
	scanf("%lld",&N);
	LL sum=0;
	for(int i=1;i<=N;i++) scanf("%lld",&P[i]),sum+=P[i];
	if(!(N&1) && (sum&1)) {printf("-1\n");return;}

	LL ans=0; LL d;
	for(int i=1;i<=N>>1;i++)
		if(P[i]!=P[N-i+1])
			if(P[i]>P[N-i+1])
			{
				d=P[i]-P[N-i+1];
				P[i]-=d;
				P[i+1]+=d;
				ans+=d;
			}
			else
			{
				d=P[N-i+1]-P[i];
				P[N-i+1]-=d;
				P[N-i]+=d;
				ans+=d;
			}
	printf("%lld\n",(N&1)?ans:ans-d/2);
}

int main()
{
#ifdef LOCAL
	freopen("D.in","r",stdin);
#endif
	int T; scanf("%d",&T);
	for(int i=1;i<=T;i++)	
		readdata();
#ifdef LOCAL
	while(1);
#endif
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值