树状数组 [Usaco2010 Nov]Cow Photographs

本文介绍USACO 2010年11月赛题“CowPhotographs”,探讨如何通过计算逆序对数量来确定最少的奶牛位置调整时间,以满足特定的排列条件。

问题 G: [Usaco2010 Nov]Cow Photographs
时间限制: 1 Sec 内存限制: 64 MB
题目描述
奶牛的图片 Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片,这样他就可以向他的朋友炫耀他的奶牛.这N只奶牛被标号为1..N. 在照相的那一天,奶牛们排成了一排.其中第i个位置上是标号为c_i(1<=c_i<=N)的奶牛.对于奶牛的站位,Farmer John有他自己的想法. FJ是这么想的,标号为i(1<=i<=n-1)的奶牛只能站在标号为i+1的奶牛的左边,而标号为N的奶牛只能站在标号为1的奶牛的左边.当然,没有牛可以站在队列中最左边的奶牛的左边了.也就是说,最左边的奶牛编号是随意的. 这些奶牛都非常的饿,急切的希望吃到FJ承诺的在拍照后的大餐,所以FJ想尽快的拍照.奶牛们的方向感非常的不好,所以FJ每一分钟只可以选择相邻的两只奶牛然后让他们交换位置.FJ最小需要多少时间就能使奶牛站成一个可以接受的序列? 比方说一个有5只奶牛的例子,一开始序列是这样的: 左边 右边 3 5 4 2 1 第一分钟,FJ可以交换第二队奶牛(即5和4),交换后的队列: 3 4 5 2 1 第二分钟,FJ交换最右边的一对,序列变成这样: 3 4 5 1 2 这样,只用了2分钟,就是序列变为了一个FJ所希望的序列.
输入
第1行:一个单独的数N 第2到n+1行:第i+1行上的数表示站在第i的位置上的奶牛的编号(即c_i).
输出
一个整数,表示是奶牛的序列变为一个合法的序列的最小花费时间.
样例输入
5

3

5

4

2

1
样例输出
2
提示

其实就是个大模拟。。。
如果设定从前到后为1~n,必按这个顺序排,那么问题就变成个求当前序列中有多少个逆序对。。搞个树状数组就好了。
那么考虑1在n后面怎么处理,可以把1视为n+1,那么1就理应排在n+1后面。那对答案有什么影响呢?只要减去1的贡献,加上n+1的贡献就行了。那么再想,当前1最小,1位置之前的数都与1构成逆序对,而n+1为当前最大,n+1位置(也就是当前1位置)后面的数都与其构成逆序对。。那对答案的更改就显而易见了。
以此类推一直求到把n-1也放到n后面,选出最小的即为ans.

#include<cstdio>
#include<iostream>
#define N 100005
#define ll long long
using namespace std;
int n,a[N],b[N],t[N];
ll ans,last;
void add(int x,int k){for(int i=x;i<=n;i+=i&(-i))t[i]+=k;}
int q(int x){int s=0;for(int i=x;i>0;i-=i&(-i))s+=t[i];return s;}
int Q(int x){return q(n)-q(x);}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]=i;
    for(int i=1;i<=n;i++)
    {
        last+=Q(a[i]);
        add(a[i],1);
    }
    ans=last;
    for(int i=1;i<n;i++)
    {
        last=last-1LL*(b[i]-1)+1LL*(n-b[i]);
        if(last<ans)ans=last;
    }
    cout<<ans;
}
P10491 [USACO09NOV] The Chivalrous Cow B 是一个涉及在二维网格中按照特定规则(类似象棋中马的走法)寻找最短路径的问题。以下是一些类似的题目: #### 洛谷 P1135 奇怪的电梯 有一个奇怪的电梯,大楼的每一层楼都可以停电梯,而且第 $i$ 层楼($1 \leq i \leq N$)上有一个数字 $K_i$($0 \leq K_i \leq N$)。电梯只有两个按钮:上和下。从第 $i$ 层楼上楼时,若按下上的按钮,则会上升 $K_i$ 层;若按下下的按钮,则会下降 $K_i$ 层。当然,电梯不能上升到超过 $N$ 层,也不能下降到低于 $1$ 层。问从 $A$ 层到 $B$ 层至少要按多少次按钮。 #### 洛谷 P1331 海战 在一个矩形的海域上,分布着一些战舰,每艘战舰由若干个相邻(上下左右相邻)的格子组成。现在给出海域的地图,问这片海域上有多少艘战舰,并且判断这些战舰的分布是否符合规则(战舰不能相邻,即两艘战舰之间至少有一个空白格子)。 #### 洛谷 P1605 迷宫 给定一个 $N \times M$ 方格的迷宫,迷宫里有一些障碍格子不能通过,从起点 $(sx, sy)$ 出发,要到达终点 $(fx, fy)$,问有多少条不同的路径可以走。只能向上下左右四个方向移动。 以下是一个简单的广度优先搜索(BFS)示例代码,用于解决类似的最短路径问题: ```python from collections import deque # 定义方向数组,上下左右 dx = [-1, 1, 0, 0] dy = [0, 0, -1, 1] def bfs(grid, start, end): rows, cols = len(grid), len(grid[0]) visited = [[False] * cols for _ in range(rows)] queue = deque([(start[0], start[1], 0)]) # (x, y, steps) visited[start[0]][start[1]] = True while queue: x, y, steps = queue.popleft() if (x, y) == end: return steps for i in range(4): new_x = x + dx[i] new_y = y + dy[i] if 0 <= new_x < rows and 0 <= new_y < cols and not visited[new_x][new_y] and grid[new_x][new_y] != '#': visited[new_x][new_y] = True queue.append((new_x, new_y, steps + 1)) return -1 # 无法到达 # 示例使用 grid = [ ['.', '.', '.', '#'], ['.', '#', '.', '.'], ['.', '.', '.', '.'], ['.', '#', '#', '.'] ] start = (0, 0) end = (3, 3) result = bfs(grid, start, end) print(result) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值