题目
题目大意
这里有 N N N只颜色为 1 , 2 , . . . , N 1,2,...,N 1,2,...,N的史莱姆,Snuke想每种颜色的史莱姆抓一只,他直接抓颜色为 i i i的史莱姆需要 a i a_i ai秒,他还可以花 X X X秒施展一个咒语,使他已经抓住的所有史莱姆的颜色加 1 1 1(颜色为 N N N的史莱姆颜色变成 1 1 1),问达成目标最少需要多少秒。
思路
如果你规定施展 k k k次咒语,那么抓住第 i i i只史莱姆可以通过抓住第 i i i只、第 i − 1 i-1 i−1只、……第 i − k + 1 i-k+1 i−k+1只或第 i − k i-k i−k只(循环计数)得到。例如,你要施展 2 2 2次咒语,捉住第 3 3 3只史莱姆,就有三种办法:
- 抓 1 1 1号 → \to →施展咒语 → \to →施展咒语
- 施展咒语 → \to →抓 2 2 2号 → \to →施展咒语
- 施展咒语 → \to →施展咒语 → \to →抓 3 3 3号
所以对于第
i
i
i只史莱姆,代价
C
(
i
,
k
)
=
min
j
=
i
−
k
i
a
j
C(i,k)=\min\limits_{j=i-k}^{i}a_j
C(i,k)=j=i−kminiaj,于是答案为:
k
X
+
∑
i
=
1
N
C
(
i
,
k
)
kX+\sum\limits_{i=1}^{N}C(i,k)
kX+i=1∑NC(i,k)
枚举
k
k
k,如果暴力计算
C
(
i
,
k
)
C(i,k)
C(i,k),时间复杂度
O
(
N
2
)
O(N^2)
O(N2)。
想想可以发现,
C
(
i
,
k
)
C(i,k)
C(i,k)能递推:
C
(
i
,
k
)
=
min
{
C
(
i
,
k
−
1
)
,
a
i
−
k
}
C(i,k)=\min\{C(i,k-1),a_{i-k}\}
C(i,k)=min{C(i,k−1),ai−k}
做完了。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 2000
int N,X;
int Cost[MAXN+5],Change[MAXN+5][MAXN+5];
int main(){
scanf("%d%d",&N,&X);
for(int i=1;i<=N;i++)
scanf("%d",Cost+i);
long long Ans=1ll<<60,tot=0;
for(int i=1;i<=N;i++)
tot+=Change[i][0]=Cost[i];
Ans=min(Ans,tot);//k=0的时候单独算,不然递推会越界
for(int k=1;k<N;k++){
tot=0;
for(int i=1;i<=N;i++)
tot+=Change[i][k]=min(Change[i][k-1],Cost[i-k<1?N+i-k:i-k]);//注意循环
Ans=min(Ans,1ll*k*X+tot);
}
printf("%lld",Ans);
}