蓝桥杯真题训练 五一 3/5
Posted iuk11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯真题训练 五一 3/5相关的知识,希望对你有一定的参考价值。
1215 小朋友排队
题目被喂了一下,知道是求逆序对的题目,一开始也想到了排序,看题解有人用归并排序做。树状数组以前学过,忘记了,看了一手代码,又会了。
二进制表示下最低位1及其后面的0构成的数值:lowbit(x) —> x & -x —> x & (~x+1) 取反加一。
有些地方都写在注释里了。那再说一下思路:
为什么做两遍树状数组,因为一个数的逆序对数,就是在它之前比它大的数,加上在它之后比它小的数。有了这个关系我们可以知道,一遍是为了求比在i之前,比当前(第i个)数大的数;一遍是为了求在i之后,比当前数小的数。所以才有了第一遍1~ n,第二遍n~ 1。
树状数组的概念就不赘述了,就是每隔2^i次计算一下前面数的和,比前缀和高级(快),跳着加,因为有lowbit这个特性。但是区间求和的时候如果左右边界不是2的倍数,还是要慢慢找一会儿,比遍历要快。(l,r)— l>=2 ^ i — r<=2 ^ i+j 就在这个(i~i+1)和(i+j-1,i+j)的区间里把累加和找出来就成,其它的区间和可以直接相减获得,和前缀和找区间和做法相同。(和这题没关系)
求出逆序对后,根据题意,每个小朋友有多少个逆序对,就交换了几次顺序,那不满意值根据逆序对个数n算一个等差数列的前n项和,再把每个小朋友的不满意值累加即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
int n;
ll a[maxn];
ll tree[maxn];
ll b[maxn];//逆序对数
int lowbit(int x){
return x&-x;
}
void add(int x,int y){
for(int i=x;i<maxn;i+=lowbit(i)) tree[i]+=y;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=tree[i];
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]++;
}
for(int i=1;i<=n;i++){
//i 表示当前插入了几个数
add(a[i],1);// 每个数插入的权值为1
b[i]=i-query(a[i]);//在i之前 有多少个比i大的数被插入
}
memset(tree,0,sizeof(tree));//再做一遍 树状数组
for(int i=n;i>=1;i--){
add(a[i],1);
b[i]+=query(a[i]-1);//在i i+1~n 有多少个数比i小
}
ll res=0;
for(int i=1;i<=n;i++){
res+=(1+b[i])*b[i]/2;//等差数列求前n项和公式
}
cout<<res;
//system("pause");
return 0;
}
1219 移动距离
#include<bits/stdc++.h>
using namespace std;
int w,m,n;
int main(){
cin>>w>>m>>n;
int x,y,xx,yy;
m--;
n--;
x=m/w;
y=m%w;
xx=n/w;
yy=n%w;
if(x%2==1) y=(w-y-1)%w;
if(xx%2==1) yy=(w-yy-1)%w;
cout<<abs(x-xx)+abs(y-yy);
//system("pause");
return 0;
}
以上是关于蓝桥杯真题训练 五一 3/5的主要内容,如果未能解决你的问题,请参考以下文章
蓝桥杯选拔赛真题51Scratch赛车训练 少儿编程scratch图形化编程 蓝桥杯选拔赛真题讲解