BZOJ1802 [Ahoi2009]checker [思维题, 动态规划]

c h e c k e r checker checker

题目描述见链接 .


正 解 部 分 \color{red}{正解部分}

可以发现当有 2 2 2 个连续的红格子出现时, 可以通过这两个红格子将棋子送达每个位置 .

于是先讨论有 2 2 2 个连续红格子的情况, 此时第一问的答案显然为 0 0 0 .
再考虑第二问的答案是什么, 可以预处理出 F [ i ] F[i] F[i] 表示在 i i i 位置放置棋子的最小代价,
i i i 位置是红格子时, F [ i ] = 1 F[i] = 1 F[i]=1, 否则初值 F [ i ] = i n f F[i] = inf F[i]=inf,
转移 F [ i ] = min ⁡ ( F [ i ] , F [ i − 1 ] + F [ i − 2 ] , F [ i + 1 ] + F [ i + 2 ] ) F[i] = \min(F[i], F[i-1]+F[i-2], F[i+1]+F[i+2]) F[i]=min(F[i],F[i1]+F[i2],F[i+1]+F[i+2]),
最后把偶数位的答案累计起来即可 .

再讨论没有 2 2 2 个连续红格子的情况, 此时第一问答案显然为偶数位的白格子个数, 第二问答案为偶数位红格子个数 .

总时间复杂度 O ( N ) O(N) O(N) .


实 现 部 分 \color{red}{实现部分}

  • 注意第一个格子即使是红色的, 也要看成白色, 因为不会在第一个格子上放棋子 .
#include<bits/stdc++.h>
#define reg register
typedef long long ll;

const int maxn = 1005;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int N;
int flag;

int A[maxn];

ll Ans_1;
ll Ans_2;
ll F[maxn];

int main(){
        scanf("%d", &N);
        memset(F, 0x3f, sizeof F);
        for(reg int i = 1; i <= N; i ++){
                scanf("%d", &A[i]); F[i] = A[i]?1:inf;
                if(i >= 3 && A[i] && A[i-1]) flag = 1;
        }
        F[1] = inf;
        if(!flag){
                for(reg int i = 2; i <= N; i += 2)
                        if(A[i]) Ans_2 ++; else Ans_1 ++;
        }else{
                F[0] = inf, F[N+1] = inf;
                for(reg int i = 1; i <= N; i ++) if(i != 1) F[i] = std::min(F[i], F[i-1]+F[i-2]);
                for(reg int i = N; i >= 1; i --) if(i != N) F[i] = std::min(F[i], F[i+1]+F[i+2]);
                for(reg int i = 2; i <= N; i += 2) Ans_2 += F[i];
                Ans_1 = 0;
        } 
        printf("%lld\n%lld\n", Ans_1, Ans_2);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值