121. 小红的区间翻转(卡码网周赛第二十五期(23年B站笔试真题))

题目链接
121. 小红的区间翻转(卡码网周赛第二十五期(23年B站笔试真题))

题目描述

小红拿到了两个长度为 n 的数组 a 和 b,她仅可以执行一次以下翻转操作:选择a数组中的一个区间[i, j],(i != j),将它们翻转。例如,对于 a = [2,3,4,1,5,6],小红可以选择左闭右闭区间[2,4],数组 a 则变成[2,3,5,1,4,6]。

小红希望操作后 a 数组和 b 数组完全相同。请你告诉小红有多少种操作的方案数。

初始 a 数组和 b 数组必定不相同。

输入

第一行输入一个正整数 n,代表数组的长度;

第二行输入 n 个正整数 ai;

第三行输入 n 个正整数 bi。

输出

选择区间的方案数。

样例1输入

4

1 2 3 1

1 3 2 1

样例1输出

2

样例2输入

4

1 1 1 1

1 1 1 1

样例2输出

6

样例3输入

10

19 2 13 71 14 14 71 40 16 23

19 2 13 71 14 14 71 40 16 23

样例3输出

2

提示

数据范围

1 ≤ n, ai ,bi ≤ 5000

在示例1中:

将 1 2 3 1 中的 2 3 进行翻转,得到 1 3 2 1。

将 1 2 3 1 整个进行翻转,得到 1 3 2 1。

所以最终结果是 2。


题解1(C++版本)

cpp 复制代码
// 区间dp
#include<bits/stdc++.h>
using namespace std;
const int N = 5010;

int n, a[N], b[N], ans;
bool dp1[N][N]; // dp1[i][j]为1表示将数组a的区间[i,j]进行翻转后,使得数组a和数组b这段区间相同
bool dp2[N][N]; // dp2[i][j]为1表示将数组a的区间[i,j]与数组b这段区间相同
int main(){
    scanf("%d", &n);
    
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
    for(int i = 1; i <= n; i++) dp2[i][i] = dp1[i][i] = true;
    for(int len = 2; len <= n; len++){ // 枚举区间长度
        for(int i = 1; i + len - 1 <= n; i++){ // 枚举区间左端点
            int j = i + len - 1; // 枚举区间右端点
            if((a[i] == b[j]) && (a[j] == b[i])){ // 将数组a的区间[i,j]进行翻转
                if(i + 1 < j) dp1[i][j] = dp1[i + 1][j - 1];
                else dp1[i][j] = true; // i和j相邻
            }
            if((a[i] == b[i]) && (a[j] == b[j])){ // 不将数组a的区间[i,j]进行翻转
                if(i + 1 < j) dp2[i][j] = dp2[i + 1][j - 1];
                else dp2[i][j] = true; // i和j相邻
            }
        }
    }
    for(int len = 2; len <= n; len++){
        for(int i = 1; i + len - 1 <= n; i++){
            int j = i + len - 1;
            bool f1 = true, f3 = true;
            if(i > 1) f1 = dp2[1][i - 1];
            if(j < n) f3 = dp2[j + 1][n];
            if(f1 && dp1[i][j] && f3) {
                ans++;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

题解2(C++版本)

cpp 复制代码
// 字符串哈希
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
 
const int N = 5005;
const uLL base = 2333;
 
uLL pw[N] = {1}, hs1[N], hs2[N], hs; // hs1表示正向求哈希,hs2表示反向求哈希, hs表示数组b的哈希
int n;
uLL a[N], b[N];
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        pw[i] = pw[i - 1] * base;
    }
    for(int i = 1; i <= n; i++) scanf("%u", &a[i]);
    for(int i = 1; i <= n; i++) scanf("%u", &b[i]), hs = hs * base + b[i];
    for(int i = 1; i <= n; i++) {
        hs1[i] = hs1[i - 1] * base + a[i];
    }
    for(int i = n ;i > 0; i--){
        hs2[i] = hs2[i + 1]*base + a[i];
    }
    //for(int i = 1; i <= n; i++) printf("%u ", hs1[i]);
    //printf("\n");
    // for(int i = 1; i <= n; i++) printf("%u ", hs2[i]);
    // printf("\n");
    int ans = 0;
    for(int i = 1; i < n; i++){
        for(int j = i + 1; j <= n; j++){
            uLL sum1 = hs1[i - 1]*pw[n - i + 1];
            uLL sum2 = (hs2[i] - hs2[j + 1]*pw[j - i + 1])*pw[n -j];
            uLL sum3 = (hs1[n] - hs1[j]*pw[n - j]);
            //printf("i = %d j = %d ", i, j);
            //printf("%u %u %u, %u \n", sum1, sum2, sum3, sum1 + sum2 + sum3);
            if(sum1 + sum2 + sum3 == hs) ans++;
        }
    }
    printf("%d\n", ans);
    return 0;
}
相关推荐
老赵聊算法、大模型备案1 小时前
北京市生成式人工智能服务已备案信息公告(2025年12月11日)
人工智能·算法·安全·aigc
CoderYanger2 小时前
C.滑动窗口-求子数组个数-越长越合法——2799. 统计完全子数组的数目
java·c语言·开发语言·数据结构·算法·leetcode·职场和发展
厕所博士2 小时前
红黑树原理前置理解—— 2-3 树
算法·2-3树·红黑树原理理解前置
萌>__<新3 小时前
力扣打卡每日一题————除自身外所有元素的乘积
数据结构·算法
xu_yule3 小时前
算法基础—搜索(2)【记忆化搜索+BFS+01BFS+Floodfill]
数据结构·算法
s09071364 小时前
Xilinx FPGA使用 FIR IP 核做匹配滤波时如何减少DSP使用量
算法·fpga开发·xilinx·ip core·fir滤波
老马啸西风4 小时前
成熟企业级技术平台-10-跳板机 / 堡垒机(Bastion Host)详解
人工智能·深度学习·算法·职场和发展
子夜江寒4 小时前
逻辑回归简介
算法·机器学习·逻辑回归
软件算法开发4 小时前
基于ACO蚁群优化算法的多车辆含时间窗VRPTW问题求解matlab仿真
算法·matlab·aco·vrptw·蚁群优化·多车辆·时间窗
another heaven4 小时前
【软考 磁盘磁道访问时间】总容量等相关案例题型
linux·网络·算法·磁盘·磁道