1. 程式人生 > >[題解]火柴排隊

[題解]火柴排隊

題目

解法

這道題實際上是一類問題:給你兩個序列 \(a(n) b(n)\),問最少花費幾步可以將\(a(n)\)變成\(b(n)\)。

如何做這種問題呢?

我們考慮這個步數要最小實際上是什麼,就是講優先順序一樣的放在兩個序列的相同位置,並且儘量讓每一個數移動的位置最少。

所以我們需要將\(a(n) 和 b(n)\)按照優先順序排序。

那排序後又怎麼做呢?

我們考慮構建一個新的陣列 \(c(n)\),其中 \( c[a[i],id] = b[i].id \)。

然後要讓 \(a(n)=b(n)\) 實際上就是要讓\(c[i]=i\) 也就是要讓b陣列中第i小的數和a陣列中第i小的數在同一個位置。

那麼這就轉化成了求解逆序對的數量了。

程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <vector>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using
namespace std; typedef long long ll; template<typename T> inline void read(T&x) { x=0;T k=1;char c=getchar(); while(!isdigit(c)){if(c=='-')k=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k; } const int maxn=1e5+15; const int mod=99999997; int n; int temp[maxn];
struct node { int h,id; bool operator < (const node& x) const { return h==x.h?id<x.id:h<x.h; } }a[maxn],b[maxn]; #define lowbits(x) (x&(-x)) ll c[maxn]; inline void add(int pos,int k) { for(int i=pos;i<=n;i+=lowbits(i)) c[i]+=k; } inline ll query(int pos) { ll re=0; for(int i=pos;i;i-=lowbits(i)) re+=c[i]; return re; } int main() { read(n); for(int i=1;i<=n;i++) read(a[i].h),a[i].id=i; for(int i=1;i<=n;i++) read(b[i].h),b[i].id=i; sort(a+1,a+1+n);sort(b+1,b+1+n); for(int i=1;i<=n;i++) temp[b[i].id]=a[i].id; ll ans=0; for(int i=1;i<=n;i++) { ll k=query(temp[i]); ans+=i-1-k; add(temp[i],1ll); } printf("%lld\n",ans%mod); return 0; }
View Code