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

checkerchecker

题目描述见链接 .


color{red}{正解部分}

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

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

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

总时间复杂度 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
%lld
", Ans_1, Ans_2);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822499.html