LA 4329(樹狀陣列)

2021-12-29 20:43:16 字數 1747 閱讀 2119

演算法競賽入門經典 p197

題目大意:

一條大街上住著n個桌球愛好者,經常比賽切磋技術。每個人都有乙個不同的技能值a[i];每場比賽需要3個人:兩名選手,一名裁判。他們有個奇怪的約定,裁判必須住在兩名選手之間,而裁判的能力值也必須在兩名選手之間。問一共能組織多少種比賽。

分析:

假設a[1]到a[i-1]中小於a[i]的數有p[i],a[i+1]到a[n]中小於a[i]的數有s[i]個;

這樣當i為裁判時能夠組織的比賽數目為:p[i]*(n-i-s[i]) + (i-1-p[i])*s[i];

則總比賽次數為:

ans = 0;

for i -> 1 to n   (i表示選取第i個人作為裁判)

ans += p[i]*(n-i-s[i]) + (i-1-p[i])*s[i];

首先確定p[i]的值,令x[j]表示到目前為止已經考慮過的所有a[i]中是否存在技能值為j的數;(x[j] = 0表示不存在,x[j] = 1表示存在)memsest(x, 0, sizeof(x));(將x初始化為0);

for i -> 1 to cur (cur為考慮的當前位置,即選取的裁判位置)

x[a[i]] = 1;

則有 p[cur] = x[1]+x[2]+.....+x[a[cur]-1];

例:假設 n = 4 a[1] = 2, a[2] = 3, a[3] = 5, a[4] = 1;

選取 cur= 3,a[cur] = 5; (第三個人做裁判)

p[3] = x[1]+x[2]+x[3]+x[4] = 0 + 1 + 1 + 0 = 2;(這裡 x[1] = 0的原因是沒有執行到第4個)

不斷的記錄求和,當然是沒有問題的(時間開銷很大)

for i -> 1 to n;

x[a[i]] = 1;

p[i] = 0;

for j -> 1 to a[i]-1

p[i] += x[j]

修改單個元素並求字首和是樹狀陣列的標準用法,可以大幅度縮減時間(時間複雜度從o(nr)降到o(nlogr) );

for i-> 1 to n

add(a[i], 1); //(點修改)

p[i] = sum(a[i]-1); //(字首和);

到這裡結果基本上可以求出來了,那s[i]呢?類似的,方向從i -> 1 to n 改為 i -> n todown 1即可;

**如下:

#include

#include

#include

using namespace std;

const int maxn = 20000+10;

const int maxm = 100000+10;

int c[maxm], a[maxn], p[maxn], s[maxn], n;

inline int lowbit(int x)

void add(int x, int d)

}int sum(int x)

return ret;

}int main()

memset(c, 0, sizeof(c));

for(int i = n; i > 0; --i)

long long ans = 0;

for(int i = 1; i <= n; ++i)

printf(%lld

, ans);

}return 0;

}

LA4329 樹狀陣列

分析 考慮第i個人當裁判。假設前i 1個人中有ci個比ai小,那麼就有 i 1 ci個比ai大 同理,設i 1到n有di個比ai小,那麼就有 n i di個比ai大。所以i當裁判有 ci n i di i ci 1 di種比賽。問題轉換為求ci和di。ci可以這麼計算 從左到右掃瞄所有的ai,令x ...

LA 4329 Ping pong 樹狀陣列

題目傳送門 這道題與樹狀陣列求逆序對的思路有些近似,是一道樹狀陣列求字首的基礎題目。我們列舉第i個人當裁判的話,假設a1到a i 1 中有ci個比ai小,那麼就有 i 1 ci個比ai大,同理,假設a i 1 到an中有di個比ai小,那麼就有 n i di個比ai大,然後根據乘法原理和加法原理,i...

LA 4329 Ping pong 樹狀陣列

樹狀陣列的典型應用,參看 演算法筆記 475頁 對於有n個數的陣列 a a 1 a n 對於每乙個元素,求出序列中,它的左邊比它小的數的個數 本題要點 1 題目見,訓練指南 197 頁 2 ans 要用 long long 3 輸入的陣列個數最大值為 20000,每個 a i 的最大值為 10000...