【AtCoder】AGC004 Colorful Slimes

版权声明:本文为博主原创文章,不管你喜不喜欢都请在注明作者后转载~( ̄▽ ̄~) https://blog.csdn.net/C20190102/article/details/82932078

题目

传送门

题目大意

这里有 N N 只颜色为 1 , 2 , . . . , N 1,2,...,N 的史莱姆,Snuke想每种颜色的史莱姆抓一只,他直接抓颜色为 i i 的史莱姆需要 a i a_i 秒,他还可以花 X X 秒施展一个咒语,使他已经抓住的所有史莱姆的颜色加 1 1 (颜色为 N N 的史莱姆颜色变成 1 1 ),问达成目标最少需要多少秒。

思路

如果你规定施展 k k 次咒语,那么抓住第 i i 只史莱姆可以通过抓住第 i i 只、第 i 1 i-1 只、……第 i k + 1 i-k+1 只或第 i k i-k 只(循环计数)得到。例如,你要施展 2 2 次咒语,捉住第 3 3 只史莱姆,就有三种办法:

  • 1 1 \to 施展咒语 \to 施展咒语
  • 施展咒语 \to 2 2 \to 施展咒语
  • 施展咒语 \to 施展咒语 \to 3 3

所以对于第 i i 只史莱姆,代价 C ( i , k ) = min j = i k i a j C(i,k)=\min\limits_{j=i-k}^{i}a_j ,于是答案为: k X + i = 1 N C ( i , k ) kX+\sum\limits_{i=1}^{N}C(i,k)
枚举 k k ,如果暴力计算 C ( i , k ) C(i,k) ,时间复杂度 O ( N 2 ) O(N^2)

想想可以发现, 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}\}
做完了。

代码

#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);
}

猜你喜欢

转载自blog.csdn.net/C20190102/article/details/82932078