【蓝桥杯集训·每日一题2025】AcWing 6135. 奶牛体检

AcWing 6135. 奶牛体检
农夫约翰的 N 头奶牛站成一行,奶牛 1 在队伍的最前面,奶牛 N在队伍的最后面。
农夫约翰的奶牛也有许多不同的品种。
他用从 1 到 N 的整数来表示每一品种。
队伍从前到后第 i 头奶牛的品种是 ai。
农夫约翰正在带他的奶牛们去当地的奶牛医院进行体检。
然而,奶牛兽医非常挑剔,仅愿意当队伍中第 i 头奶牛为品种 bi 时对其进行体检。
农夫约翰很懒惰,不想完全重新排列他的奶牛。
他将执行以下操作恰好一次。
选择两个整数 l 和 r,使得 1≤l≤r≤N。反转队伍中第 l 头奶牛到第 r 头奶牛之间的奶牛的顺序。
农夫约翰想要衡量这种方法有多少效果。
对于每一个 c=0…N,请帮助农夫约翰求出使得恰好 c 头奶牛被检查的不同操作 (l,r)的数量。
两种操作 (l1,r1)
和 (l2,r2) 不同,如果 l1≠l2 或者 r1≠r2
输入格式
输入的第一行包含 N
第二行包含 a1,a2,…,aN
第三行包含 b1,b2,…,bN
输出格式
输出 N+1 行,第 i 行包含使得 i−1 头奶牛被检查的不同操作 (l,r)的数量。
数据范围
1≤N≤7500
1≤ai,bi≤N
在这里插入图片描述
(枚举)
暴力的想法,枚举所有的区间,记录下如果翻转该区间后会有多少个 a[i]==b[i] ,记为 sum
首先,要记录原序列下有多少个 a[i]==b[i] ,因为翻转区间是在原序列基础上进行,将为影响原序列 sum 的变化。
如果是常规的枚举左端点再枚举右端点时间复杂度已经是 O(n2),然后要处理每个区间翻转后影响,最后时间复杂度会是 O(n3) ,会超时不可行。
所以不要单纯枚举区间端点,而是从一个点开始向左右扩展,这时对于 [l,r] 我们已知 [l+1,r−1] 的 sum,就只需思考新扩展的两个整数 a[l]和a[r] 在翻转后的影响,直到区间的某个端点到了边界后结束。
思考a[l]和a[r] 在翻转后的影响:
如果 a[l]=b[l] ,翻转就要减去这条记录,即 sum–
如果 a[r]=b[r] ,翻转就要减去这条记录,即 sum–
如果 a[l]=b[r] ,翻转就要加上这条记录,即 sum++
如果 a[r]=b[l] ,翻转就要加上这条记录,即 sum++
特别的,对于奇数和偶数区间要分别枚举。
最后,每个区间翻转后的 sum 即是恰好有 sum 个 a[i]==b[i] 的一个答案,用一个数组来记录每个 sum 有多少个,就是答案。
时间复杂度 O(n2)
java

import java.util.Scanner;
public class Main{
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        //sc.nextLine(); // 清除残留的换行符
        
        int []a=new int[7510];
        int []b=new int[7510];
        for(int i=0;i<n;i++)
            a[i]=sc.nextInt();
        for(int i=0;i<n;i++)
            b[i]=sc.nextInt();
        int cnt=0;
        for(int i=0;i<n;i++){
            if(a[i]==b[i])
                cnt++;
        }
        int []ans=new int[7510];
        for(int i=0;i<n;i++){
            for(int j=0;j<2;j++){
                int sum=cnt;
                for(int l=i,r=i+j;l>=0&&r<n;l--,r++){
                    if(a[l]==b[l])
                        sum--;
                    if(a[r]==b[r])
                        sum--;
                    if(a[l]==b[r])
                        sum++;
                    if(a[r]==b[l])
                        sum++;
                    ans[sum]++;
                }
            }
        }
        for(int i=0;i<=n;i++){
            System.out.println(ans[i]);
        }
    }
}

不需要sc.nextLine()代码能正确运行的原因
输入格式的巧合性
当输入的n和数组数据按照以下格式排列时:

3
1 3 2
3 2 1

n=3后的换行符会被后续的nextInt()自动跳过。
数组a和b的数据位于独立行,nextInt()会直接跳过换行符并读取下一行的数值。
nextInt()的特性
nextInt()在读取数字时,会忽略所有前导的空白字符(包括换行符),因此即使不调用sc.nextLine(),也能正确读取后续行的数据。
为什么不需要sc.nextLine()?
测试用例的特殊性
题目中的输入数据严格按以下格式排列:
第一行是n
第二行是数组a的n个数字
第三行是数组b的n个数字
这种情况下,nextInt()会按预期跳过换行符,直接读取后续行的数值。
潜在风险
如果输入数据格式不符合预期(例如,n和数组a在同一行),或者存在多余的空格/换行符,代码可能抛出NoSuchElementException。例如:

3 1 2 3 4 5 6

这种输入会导致n=3后的数字被错误地读入数组a和b,最终导致逻辑错误。
安全做法
为了代码的健壮性,建议始终在nextInt()后调用sc.nextLine():

int n = sc.nextInt();
sc.nextLine(); // 清除残留的换行符

这样能确保输入流的正确对齐,避免因输入格式变化导致的意外错误。
总结
你的代码能正确运行是因为测试用例的输入格式恰好符合nextInt()的自动跳转特性。虽然在此特定场景下不需要处理换行符,但为了代码的通用性和可靠性,显式清除换行符是更安全的做法。
c++
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值