演算法競賽入門經典 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...