uoj A. 【UER #7】短路 (贪心)

A. 【UER #7】短路



“第七套广播体操,原地踏步——走!”

众所周知,跳蚤们最喜欢每天早起做早操,经常天还没亮就齐刷刷地站在操场做着反复纵跳热热身。跳晚国在研制三星 note7 的时候注意到了这点,于是他们打算让炸弹更快地引爆,这样就可以消灭更多早起的跳蚤。

三星 note7 的主板可以看作是由  (2n+1)×(2n+1) (2n+1)×(2n+1) 个中继器构成的,某些中继器会有导线连在一起,左上角和右下角的中继器分别连着电源的正负极。

电流流过一根导线的时间可忽略不计,但当电流经过中继器时,会延缓一段时间再从中继器流出。这个时间只跟该中继器本身有关,我们把这段时间的长度称为中继器的延时值。

这些中继器由导线连接围成一个一个的层,同个层的中继器的种类都一样,而不同层的种类都不一样,可以发现总共有  n+1 n+1 层。当  n=4

n=4 时,主板大概长这样


跳晚们打算再加几根导线将某些中继器连接起来.凭借发达的重工业,他们能生产出无数条导线。但由于主板的限制,他们的导线只能和主板四周的边平行,且其长度只够连接相邻两个中继器。

现在他们想知道,他们改造的三星 note7 的电源正极流出的电流能在多短的时间到达电源负极从而造成短路,这样电池就会释放出巨大的能量摧毁跳蚤国的有生力量了。

请参考输入格式和样例配图来更好地理解题意。

输入格式

第一行一个正整数  n n

第二行  n+1 n+1 个正整数  a0,a1,,an a0,a1,…,an,表示从内到外每层的中继器的延时值,单位为秒。其中,第  i i 行第  j j 列的中继器的延时值为(1<=i,j<=n)    

输出格式

输出一行一个数表示改造后的最短引爆时间。

C/C++ 输入输出 long long 时请用 %lld。C++ 可以直接使用 cin/cout 输入输出。

样例一

input
1
 1 2

output
9

explanation

这个数据对应的主板如下所示:                                               显然,我们可以用导线改造成这样:

                                  

这样从左上角到右下角就会有条  {2,2,1,2,2} {2,2,1,2,2} 的电流路径,耗时为  9 9 秒。

样例二

input
9
    9 5 3 7 6 9 1 8 2 4

output
69

限制与约定




题解:贪心
算法一 
直接暴力 dfs,复杂度指数级,期望得分 10 分。 
算法二 
用最短路算法,复杂度 O(n2logn) ,根据实现情况可以获得 10 至 30 分。 
算法三 
只能往下或者往右走这是显然的叭?所以一个二维dp就可以了,时间复杂度 O((2n+1)2) 。期望得分30分。 
算法四 
由于这个正方形是完全中心对称的,所以我们只需要考虑走1/4个就可以了,再加一个滚动数组可以做到 O(n(2n+1)) ,期望得分50分。 
算法五 
如果从外向里某一层的 ai 为它之前所有 ai 的最小值的话,那么称它为可以成为前缀最小值得一层。 
最终最优的路径应该为将所有前缀最小值的层的左上角的点用若干个“L”连接起来所得到的路径。 
正确性是显然的。如果要从第一层的左上角到达第i层的任意一点的话,它们中间的每一层都至少经过一次。那么如果有一层不是前缀最小值的话,那么这一层的路径一定可以通过上移或左移然后被它之前的最小值的那一层的路径代替,使答案更优。所以只有能成为前缀最小值的层才可能经过大于1个点,其余的层数都只能经过一个点。 
那么,我们可以暴力枚举最深到达的哪一层,最深的一层一定是从左上角进入,走一个“L”形再从右下角出去,所以我们可以每次转移的时候就是到达上一个前缀最小值的左上角的值+中间穿越的非前缀最小值点*1+从上个前缀最小值的左上角到达当前层穿越的点数*上一个前缀最小值的权+当前的L,处理当前的L其他的根据对称性都要*2.


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 100003
#define LL  long long 
using namespace std;
int n,m;
LL a[N],num[N],maxn;
int main()
{
	scanf("%d",&n);
	for (int i=0;i<=n;i++) scanf("%I64d\n",&a[i]),maxn=max(a[i],maxn);
	LL minn=maxn+1; LL sum=0; int pos=n; LL ans=maxn*(4*(n+1)-1); LL last=0;
	for (int i=n;i>=0;i--)
	 if (a[i]<minn){
	 	LL now=last+sum+(2*i+1)*a[i]+minn*(pos-i);
	 	now*=2;  now-=a[i];
	 	ans=min(ans,now);
	 	last=last+sum+a[i]+minn*(pos-i);
	 	minn=a[i]; pos=i;
	 	sum=0; 
	 }
	 else sum+=a[i];
	printf("%I64d\n",ans);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值