用一个双向链表来查找比当前元素大的前k-1个元素和后k-1个元素 ,从小到大枚举x,算完x的贡献后将x从链表中删除,优化到O(nk)。
/*hdu6058[链表维护] 2017多效3*/ #include <bits/stdc++.h> using namespace std; typedef long long LL; int T, n, k, temp; int pos[500005], pre[500005], nxt[500005]; LL a[500005], b[500005]; LL ans = 0; LL Getans(int x) { int r1 = 0, r2 = 0; LL ret = 0; for (int i = x; i >= 0 && r1 <= k; i = pre[i]) { a[++r1] = i - pre[i];//向前找k-1个比当前元素大的 } for (int i = x; i <= n && r2 <= k; i = nxt[i]) { b[++r2] = nxt[i] - i;//向后找k-1个比当前元素大的 } for (int i = 1; i <= r1; i++) { if (k - i + 1 <= r2 && k - i + 1 >= 1) { //cout << x << ' ' << a[i] << ' ' << b[k - i + 1] << endl; ret += a[i] * b[k - i + 1]; } } return ret; } void del(int i) { pre[nxt[i]] = pre[i]; nxt[pre[i]] = nxt[i]; } void connect(int u, int v) { nxt[u] = v; pre[v] = u; } void solve() { for (int i = 0; i <= n; i++) connect(i, i + 1); for (int i = 1; i <= n; i++) { ans += Getans(pos[i]) * i; del(pos[i]);//每次删去一个, 保证其他所有元素都比当前元素大 } printf("%lld ", ans); } int main() { scanf("%d", &T); while (T--) { ans = 0; scanf("%d %d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d", &temp); pos[temp] = i; } solve(); } return 0; }