inv 牛客网多校

2024-02-22 18:48
文章标签 牛客 inv 网多校

本文主要是介绍inv 牛客网多校,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://www.nowcoder.com/acm/contest/143/D

给一个1 3 ... n-1的a序列 和一个2 4 ... n的排列的b序列 问归并后最小逆序对数 肯定考虑用a插b 因为a是有序的(无脑解释)

首先有个结论 a序列插入时 a[i+1]插入的最优位置一定在a[i]的右边

//(1,i)|(b[j]>a[i]) 代表[1,n]内有多少b[j]大于a[i]

对于每个a[i] 找一个p使(1,i)|(b[p]>a[i])+(i+1,n)|(b[p]<a[i])最小 该式子可以化为a[i]/2+( (1,i)|(b[p]>a[i])-(1,i)|(b[p]<a[i]) ) 设对于i来说 f[i][j]=( (1,i)|(b[j]>a[i])-(1,i)|(b[j]<a[i]) ) 即我们需要在f[i][1] ... f[i][n]内选一个最小值作为最优解

当i==1是 显然f[i][1]是最小的 当i>1时我们需要根据f[i-1][1] ... f[i-1][n]来得出f[i][1] ... f[i][n]

假设a[i]=2*i-1 a[i+1]=2*i+1 且b序列中2*i这个数的位置在v

(1) 对于j>=v 之前在i-1时 a[i-1]=2*i-1<b[v]=2*i 而现在变为a[i]=2*i+1>b[v]=2*i 也就是b[v]由(1,i)|(b[j]>a[i])-(1,i)|(b[j]<a[i])的左边跑的了右边 此消彼长 f[i][j]=f[i-1][j]-2

(2) 对于i<v b[v]并没有造成什么影响 故f[i][j]=f[i-1][j]

这样每次对一个后缀[v,n]减二 最后取个min即可

最巧的地方在于a是全奇 b是全偶 枚举a时每次只增加2 只用考虑夹在a[i-1]与a[i]之间的那个b值即可

至于为什么会有 a序列插入时 a[i+1]插入的最优位置一定在a[i]的右边 我的理解是因为每次对一个后缀减二 所以每次更新后的f[i]是递减的 所以最优解肯定出现在右边(强行解释)

#include <bits/stdc++.h>
using namespace std;
#define ll long longstruct node
{int l;int r;ll val;ll laz;
};node tree[400010];
int ary[100010],pos[100010];
int n;void buildI(int l,int r,int cur)
{int m;tree[cur].l=l;tree[cur].r=r;tree[cur].val=0;if(l==r) return;m=(l+r)/2;buildI(l,m,2*cur);buildI(m+1,r,2*cur+1);
}ll queryI(int pl,int pr,int cur)
{ll res;if(pl<=tree[cur].l&&tree[cur].r<=pr){return tree[cur].val;}res=0;if(pl<=tree[2*cur].r) res+=queryI(pl,pr,2*cur);if(pr>=tree[2*cur+1].l) res+=queryI(pl,pr,2*cur+1);return res;
}void updateI(int tar,int cur)
{tree[cur].val++;;if(tree[cur].l==tree[cur].r) return;if(tar<=tree[2*cur].r) updateI(tar,2*cur);else updateI(tar,2*cur+1);
}void pushup(int cur)
{tree[cur].val=min(tree[2*cur].val,tree[2*cur+1].val);
}void pushdown(int cur)
{if(tree[cur].laz!=0){tree[2*cur].val+=tree[cur].laz;tree[2*cur].laz+=tree[cur].laz;tree[2*cur+1].val+=tree[cur].laz;tree[2*cur+1].laz+=tree[cur].laz;tree[cur].laz=0;}
}void buildII(int l,int r,int cur)
{int m;tree[cur].l=l;tree[cur].r=r;tree[cur].val=l;tree[cur].laz=0;if(l==r) return;m=(l+r)/2;buildII(l,m,2*cur);buildII(m+1,r,2*cur+1);
}void updateII(int pl,int pr,int cur)
{if(pl<=tree[cur].l&&tree[cur].r<=pr){tree[cur].val-=2;tree[cur].laz-=2;return;}pushdown(cur);if(pl<=tree[2*cur].r) updateII(pl,pr,2*cur);if(pr>=tree[2*cur+1].l) updateII(pl,pr,2*cur+1);pushup(cur);
}int main()
{ll ans;int i;scanf("%d",&n);for(i=1;i<=n/2;i++){scanf("%d",&ary[i]);pos[ary[i]/2]=i;}buildI(1,n/2,1);ans=0;for(i=1;i<=n/2;i++){ans+=queryI(ary[i]/2,n/2,1);updateI(ary[i]/2,1);}//printf("***%lld***\n",ans);buildII(0,n/2,1);for(i=1;i<=n/2;i++){ans+=((i-1)+tree[1].val);updateII(pos[i],n/2,1);}printf("%lld\n",ans);return 0;
}

 

这篇关于inv 牛客网多校的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/736166

相关文章

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比

笔试强训,[NOIP2002普及组]过河卒牛客.游游的水果大礼包牛客.买卖股票的最好时机(二)二叉树非递归前序遍历

目录 [NOIP2002普及组]过河卒 牛客.游游的水果大礼包 牛客.买卖股票的最好时机(二) 二叉树非递归前序遍历 [NOIP2002普及组]过河卒 题里面给的提示很有用,那个马的关系,后面就注意,dp需要作为long的类型。 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息publ

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和(递归深搜) 解析代码 牛客_求和(递归深搜) 求和_好未来笔试题_牛客网 解析代码         递归中每次累加一个新的数,如果累加和大于等于目标,结束递归。此时如果累加和正好等于目标,则打印组合。向上回退搜索其它组合。此题本身就是一个搜索的过程,找到所有的组合。 #include <iostream>#include <cmath>#in

牛客《剑指Offer》 -- 数值的整数次方

题目描述 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 思路 特别注意负数的情况,出现负数,将其转化为正数然后求倒数。 class Solution {public:double Power(double base, int exponent) {double total = 1;bool flag = false

牛客网《剑指Offer》 二进制中1的个数

题目描述 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 思路 负数用补码,其实就是求一个数据在计算机中是存储是怎么样子的。用位运算,就能很好实现。 class Solution {public:int NumberOf1(int n) {int count = 0;int flag = 1;while (flag != 0) {if ((n & f

牛客网《剑指Offer》 矩形覆盖

题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? class Solution {public:int rectCover(int number) {if(number==0) return 0;if(number==1) return 1;if(number==2) return 2;retu

牛客《剑指Offer》 变态跳台阶

题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 思路 根据 普通的跳台阶可以总结出 f(n) = f(n-1) + f(n-2) +f(n-3) + 。。。。+ f(1) +1 不妨设 f(0) = 1 , 则易得 class Solution {public:int jumpFloorII(int n

牛客《剑指Offer》 跳台阶

题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 思路 递归思想,n阶梯子走法等于n-1 加上n-2的。 class Solution {public:int jumpFloor(int number) {if(number==1) return 1;if(number==2) return 2;return jumpFl