0816 京东笔试答案-减小逆序对-跳水运动

题目一:减小逆序对

题目简介:减少逆序对,给t组测试数据,每组给一个n,给一个序列A:a1,a2,a3...an;可以做的操作是在A序列的[L,R]范围上+1,且该操作只能做一次,使用该操作最多能让逆序对减少多少。

思路:首先给[L,R]范围上+1使得逆序对减少,那么带来的影响是会让[0,L-1]上的逆序对减少,但是也可能会让[R+1,N]范围上的逆序对增多,所以对于任意的[L,R] -->[L,N]一定是优于或者等于[L,R]的答案的,因为即没有影响正向影响,同时也取消了负面影响.

代码实现思路:dp[i] = 以i当成L的情况下带来的影响,那么dp[i] = {[0,i-1]所有值等于a[i] + 1的个数} + dp[i+1] -

{[i+1,n]所有值等于a[i]-1 的值}

也就是说在计算{[0,i-1]所有值等于a[i] + 1的个数}的时候所有满足条件的j在dp[j]处也会-1,因为随着i倒序向前增长,i的范围扩大

的同时,本来给当前i造成贡献的位置j,在dp[j]的时候因为+1了所以要减掉在i的时候造成的贡献。

例如 在dp[5] 的时候应该等于{前面 [0,4] 范围中所有值等于a[5] + 1的数的个数} + dp[6] - {[6,N]中所有值等于a[5] - 1}的数就是dp[5]的答案。

但是后面这一步是不用减的因为在前面的某一步中例如a[5]的值刚好等于a[i]+1那么在操作dp[i]的时候会顺便把dp[5]--,就是这个意思。

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N],t,n,dp[N];
vector<int> cnt[N];
int main(){
    cin>>t;
    while(t--){
        cin>>n,memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)cin>>a[i],cnt[a[i]].clear(),cnt[a[i]+1].clear();
        for(int i=1;i<=n;i++)cnt[a[i]].push_back(i);
        for(int i=n;i>0;i--){
            dp[i]+=dp[i+1];
            for(auto j:cnt[a[i]+1]) if(j<i) dp[j]--,dp[i]++;
        }
        int ans = 0;
        for(int i=1;i<=n;i++)ans = max(ans,dp[i]);
        cout<<ans<<endl;
    }
}

题目二:跳水运动

这题就是滑动窗口+前缀和就不说了。

#秋招白月光##笔试#
全部评论

相关推荐

------------------------------------题目一:题目大意:给定一个长度为&nbsp;n&nbsp;(1&nbsp;&lt;=&nbsp;n&nbsp;&lt;=&nbsp;1e5)&nbsp;的序列&nbsp;a&nbsp;(1&nbsp;&lt;=&nbsp;a[i]&nbsp;&lt;=&nbsp;n)。你可以执行最多一次操作:选择一个连续区间&nbsp;[L,&nbsp;R],将区间内所有数字加1。你的目标是最大化操作后能减少的逆序对(能量冲突)数量。(T&nbsp;组数据)解法思路:核心是分析区间加一操作对逆序对的影响。一个逆序对&nbsp;(i,&nbsp;j)&nbsp;会被消除,当且仅当&nbsp;i&nbsp;不在区间内,j&nbsp;在区间内,且&nbsp;a[i]&nbsp;=&nbsp;a[j]&nbsp;+&nbsp;1。反之,如果&nbsp;i&nbsp;在区间内,j&nbsp;不在区间内,且&nbsp;a[i]&nbsp;=&nbsp;a[j],则会产生新的逆序对。为了避免产生新的逆序对,最优策略是选择一个后缀区间&nbsp;[L,&nbsp;n]&nbsp;进行操作。问题转化为,对于每个&nbsp;L,计算选择后缀&nbsp;[L,&nbsp;n]&nbsp;能消除多少逆序对。这可以通过从后向前遍历&nbsp;L,同时用两个计数数组分别维护&nbsp;L&nbsp;前后各个数值的出现次数,在&nbsp;O(n)&nbsp;时间内计算出每个&nbsp;L&nbsp;对应的收益,从而找到最大值。------------------------------------题目二:题目大意:有&nbsp;n&nbsp;(3&nbsp;&lt;=&nbsp;m&nbsp;&lt;=&nbsp;n&nbsp;&lt;=&nbsp;1e5)&nbsp;位评委,给出&nbsp;n&nbsp;个评分。你需要在这&nbsp;n&nbsp;个评分中,找到一个长度为&nbsp;m&nbsp;的连续区间,使得去掉该区间中的一个最高分和一个最低分后,剩下&nbsp;m-2&nbsp;个分数的平均值最大。输出这个最优区间的起始位置(1-indexed)。如果平均值相同,选择起始位置最小的。解法思路:由于分母&nbsp;m-2&nbsp;是固定的,最大化平均值等价于最大化分子,即&nbsp;`区间和&nbsp;-&nbsp;区间最大值&nbsp;-&nbsp;区间最小值`。这个问题可以用滑动窗口来解决。维护一个长度为&nbsp;m&nbsp;的窗口,从左到右滑过整个评分数组。为了能在窗口滑动时(增加一个元素,删除一个元素)高效地找到最大值和最小值,需要一个支持快速增删和查询极值的数据结构。C++&nbsp;中的&nbsp;`multiset`&nbsp;或&nbsp;Java&nbsp;中的&nbsp;`TreeMap`&nbsp;非常适合此场景,它们可以在&nbsp;O(log&nbsp;m)&nbsp;的时间内完成操作。因此,总的时间复杂度为&nbsp;O(n&nbsp;log&nbsp;m)。在滑动过程中,不断更新最大得分和对应的起始位置即可。z具体的详细代码和题解可以戳我主页的文章查看
投递京东等公司10个岗位
点赞 评论 收藏
分享
今天 15:52
Python
爱睡觉的冰箱哥:硬气一点,不卑不亢别舔的太难看
点赞 评论 收藏
分享
评论
3
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务