1魔法巡游

 题目理解

//两个连续的需需要包含共鸣元素

//比如前一个有0,2,4。则后一个至少0,2,4中一个

//前一个有0,2则后一个至少有0或2.

//前一个有0后一个必须有0



//使用条件为序号大,不是数值大
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n , a[N] , b[N] , dp1[N][3] , dp2[N][3];

// 获取数字对应的共鸣元素索引,0对应0,2对应1,4对应2
int get(int x){
    if(x == 0) return 0;
    if(x == 2) return 1;
    if(x == 4) return 2;
}

int main(){
    // 输入符文石的数量
    cin >> n;
    // 输入小蓝的符文石上的数字
    for(int i = 1 ; i <= n ; i ++){
        cin >> a[i];
    }
    // 输入小桥的符文石上的数字
    for(int i = 1 ; i <= n ; i ++){
        cin >> b[i];
    }
    // 初始化dp数组为负无穷,表示初始状态不可达
    memset(dp1, -0x3f , sizeof(dp1));
    memset(dp2, -0x3f , sizeof(dp2));
    // 初始化小桥未使用符文石时的状态
    //小蓝的初始化之后不能够全过
    for(int j = 0 ; j < 3 ; j ++) dp2[0][j] = 0;
    // 遍历每个符文石
    for(int i = 1 ; i <= n ; i ++){
        // 初始化当前符文石的状态为前一个符文石的状态
        //这里的状态就是长度
        //将前一个长度给后一个长度,表示用不用长度都一样
        for(int j = 0 ; j < 3 ; j ++) {
            dp1[i][j] = dp1[i - 1][j];//dp1[N][3]一个N行3列数组
            dp2[i][j] = dp2[i - 1][j];//dp2[N][3]一个N行3列数组
        }

        // 处理小蓝的符文石
        int x = a[i] , y = b[i] , ma = -0x3f3f3f3f;
        set<int>se;
        // 获取小蓝符文石上的共鸣元素
        //当i=1时表示现在正在检查的是小蓝第一个元素
        while(x){ 
            if(x % 10 == 0 || x % 10 == 2 || x % 10 == 4) se.insert(get(x % 10));       
            x /= 10;//将x的共鸣元素放在了set容器里
        }
        // 更新dp1数组,表示小蓝使用当前符文石后能达到的最长巡游序列长度
        //然后用范围内的共鸣元素检查最长长度
        //如(2,4)
        //则下一行代码表示
        //小桥用i-1个且共鸣元素为2的长度与
        //小桥用i-1个且共鸣元素为4的长度谁大谁给ma
        //然后将这个最大的新值和原来的旧值取最大值
        for(auto k : se) ma = max(ma , dp2[i - 1][k]);
        for(auto k : se) dp1[i][k] = max(dp1[i][k] , ma + 1);
        //类似于01背包将新旧值进行取大
        // 清空集合,处理小桥的符文石
        //下一步该小桥了
        se.clear() , ma = -0x3f3f3f3f;
        // 获取小桥符文石上的共鸣元素
        while(y){
            if(y % 10 == 0 || y % 10 == 2 || y % 10 == 4) se.insert(get(y % 10));
            y /= 10;
        }
        // 更新dp2数组,表示小桥使用当前符文石后能达到的最长巡游序列长度
        for(auto k : se) ma = max(ma , dp1[i - 1][k]);//遍历所有共鸣元素情况,取所有可能中最大值
        for(auto k : se) dp2[i][k] = max(dp2[i][k] , ma + 1);//原来的大还是新的大
    }
    // 计算最终结果,即最长时空巡游序列的长度
    int res = 0;
    for(int j = 0 ; j < 3 ; j ++) res = max(res , max(dp1[n][j] , dp2[n][j]));
    //因为能选的元素只有共鸣元素,所以以这三个结尾的长度看看谁最长
    //因为n长度不知道,最后一步可能是小桥也可能是小蓝所以两个数组都要比较,
    //如果最后一个人是固定一个人走的话就只要比较一个人的三种情况了
    //dp1[i][j]的含义:第i个来自于1号含有共鸣元素j的
    //dp1[n][j]:甲使用第n个并且元素为j的长度
    //dp2[n][j]:乙使用第n个且元素为j的长度
    
    // 输出结果
    cout << res << '\n';
    return 0;
}
/*
dp1[i][j]表示长度为i的序列中最后一个来自于小蓝
dp2[i][j]表示长度为i的序列当中最后一个来自于小桥
状态转移方程
如果有2,4
dp1[i][j]=dp2[i-1][2]+dp2[i-1][4]
对于一个元素,将其每一位放到一个unorderedset
将dp1[]和dp2[]中需要比较的数进行拆分

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值