你知道什么是数据结构吗?反正我不知道。

本文探讨了两道编程竞赛题目,一是利用树状数组计算序列逆序对之和,二是设计高效算法求解特定区间内柱子序列的可见度。通过算法优化和数据结构选择,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好吧今天又考试了,idy002之光不灭……考试时蜜汁样例数据坑死一片,idy估计是午觉没睡好出的题。

第一题,树状数组。

那么它的一个逆序对是一个二元组:< i; j > 满足i < j 且ai > aj,其中i; j 2 [1; n]。
我们称一个序列所包含的逆序对的个数为这个序列的逆序对数。
那么问题来了:
我给出一个长度为n 的序列,需要你计算:

a1, a2……an-1, an

aa3 ……an, a1

a3, a4……a1, a2

……

an, a1…… an-2,an-1

这n 个序列的逆序对之和。

Input
输入文件包含2 行:
第1 行1 个整数:n,表示给定序列的长度。
第2 行n 个整数:a1 a2 : : : an,表示初始序列。
Output
输出n 个序列的逆序对的和。

(样例有坑,input 3 2 2 3 output 3)

#include "cstdio"
#include "cstring"
#include "algorithm"
#define N 1000010
using namespace std;
int a[2 * N], bit[N * 24], n, m;
long long ans = 0, cur = 0;
int lowbit( int x ){
	return x & ( -x );
}
/*void modify( int pos, int delta ){
	for( int i = pos; i <= n; i += lowbit( i ) )
		bit[i] += delta;
}
int query( int rg ){
	int rt = 0;
	for( int i = rg; i; i -= lowbit( i ) )
		rt += bit[i];
	return rt;
} *//两种树状数组
void modify(int pos,int delta){
	int x=pos;
	while(x<=n){
		bit[x]+=delta;
		x+=lowbit(x);
	}
}
int query(int pos){
	int x=pos,rt=0;
	while(x){
		rt+=bit[x];
		x-=lowbit(x);
	}
	return rt;
}
int main(){
	freopen("rotinv.in", "r", stdin);
	freopen("rotinv.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
		a[ n + i ] = a[i];
	}
	for(int i = 1; i <= n; i++){
		cur += (i - 1) -query( a[i] );
		modify( a[i], +1 );
	}
	for(int i = n + 1; i <= n + n; i++){
		modify( a[i-n], -1);
		cur += (n - 1) -query( a[i] );
		cur -= query( a[i - n] - 1 );
		modify( a[i], +1 );
		ans += cur;
	}
	printf("%I64d", ans);
	return 0;
}


第二题,不知道是什么听起来非常高端的数据结构。

你有一堆柱子,它们竖直地并排摆放在桌子上,它们的高度分别是:
h1,h2……hn-1,hn
你从前往后看,能够看见的柱子个数为这个柱子序列的“可见度”(能够看见柱子i 当且仅当hj < hi任意j < i)。
现在给你一个长度为n 的序列,还有m 个询问,每次询问某个区间[l, r] 的柱子单独拿出来后,其可见度是多大。
Input
第1 行2 个整数:n m,表示给出的柱子序列的长度和询问数。
第2 行n 个整数:a1,a2……an-1,an,表示每根柱子对应的高度。
接下来m 行,每行2 个整数:l r,表示对区间[l,r] 进行询问。

input

5 4

1 3 2 4 2

1 4

2 4

1 3

2 3

output

3

2

2

1

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
using namespace std;

int n,m,tot=0;
int a[N],head[N],q[N],b[N];

struct node{
	int pre,to;
}edge[N];

void adde(int from,int to){
	tot++;
	edge[tot].pre=head[from];
	edge[tot].to=to;
	head[from]=tot;
}

int dfs(int u,int r){
	for(int i=head[u];i;i=edge[i].pre){
		int v=edge[i].to;
		if(v<=r){
		    dfs(v,r);
		    tot++;
		}
	}
	return tot;
}

int main(){
	freopen("rise.in","r",stdin);
	freopen("rise.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(register int i=1;i<=n;i++){
		for(register int j=i+1;j<=n;j++){
			if(a[j]>a[i]){
				adde(i,j);
				break;
			}
		}
	}
	while(m--){
		int u,v;
		tot=1;
		scanf("%d%d",&u,&v);
		printf("%d\n",dfs(u,v));
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值