HDU多校第四场1005 Didn‘t I Say to Make My Abilities Average in the Next Life?! 单调栈+莫队

原题链接:https://acm.hdu.edu.cn/showproblem.php?pid=6989

题意

给你一个数列,定义一个区间的平均值为(Max+Min)/2,询问一个区间的所有平均值的期望是多少。

分析

我们把题目的式子化简一下,就是 ∑ m a x + ∑ m i n 2 ∗ l e n ∗ ( l e n + 1 ) 2 \frac{\sum max+\sum min}{2*\frac{len*(len+1)}{2}} 22len(len+1)max+min
= ∑ m a x + ∑ m i n l e n ∗ ( l e n + 1 ) =\frac{\sum max+\sum min}{len*(len+1)} =len(len+1)max+min

这样我们只需要求出所有子区间的最大值和所有子区间的最小值之和就可以了。
对于这类问题,我在这篇文章中详细解释过(双倍经验点这里
接下来就是套个板子的事情。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<ll, ll> PII;
const ll inf = 1e18;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;

#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\n'

namespace StandardIO {
    template<typename T>
    inline void read(T &x) {
        x = 0; T f = 1;
        char c = getchar();
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }

    template<typename T>
    inline void write(T x) {
        if (x < 0) putchar('-'), x *= -1;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + '0');
    }
}
namespace Comb {
    ll f[N];
    ll ksm(ll a, ll b) {
        ll res = 1, base = a;
        while (b) {
            if (b & 1) res = res * base % mod;
            base = base * base % mod;
            b >>= 1;
        }
        return res;
    }
    void init() {
        f[0] = 1;
        for (ll i = 1; i < N; i++) f[i] = f[i - 1] * i % mod;
    }
    ll C(ll a, ll b) {
        if (a < 0 || b < 0 || b > a) return 0;
        return f[a] * ksm(f[a - b], mod - 2) % mod * ksm(f[b], mod - 2) % mod;
    }
}

namespace ST {
    int mi[N][21], ma[N][21], lg[N], a[N];
    int cmp1(int x, int y) {
        return a[x] < a[y] ? x : y;
    }
    int cmp2(int x, int y) {
        return a[x] > a[y] ? x : y;
    }
    void init(int n) {
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            ma[i][0] = mi[i][0] = i, lg[i] = log2(i);
        }
        for (int i = 1; i <= 20; i++) {
            for (int j = 1; j + (1 << i) - 1 <= n; j++) {
                mi[j][i] = cmp1(mi[j][i - 1], mi[j + (1 << (i - 1))][i - 1]);
                ma[j][i] = cmp2(ma[j][i - 1], ma[j + (1 << (i - 1))][i - 1]);
            }
        }
    }
    int qry_mi(int l, int r) {
        int k = lg[r - l + 1];
        return a[cmp1(mi[l][k], mi[r - (1 << k) + 1][k])];
    }
    int qry_ma(int l, int r) {
        int k = lg[r - l + 1];
        return a[cmp2(ma[l][k], ma[r - (1 << k) + 1][k])];
    }
    int qry_pmi(int l, int r) {
        int k = lg[r - l + 1];
        return cmp1(mi[l][k], mi[r - (1 << k) + 1][k]);
    }
    int qry_pma(int l, int r) {
        int k = lg[r - l + 1];
        return cmp2(ma[l][k], ma[r - (1 << k) + 1][k]);
    }
}
using namespace ST;
using namespace Comb;
int n, m, pos[N], lmi[N], rmi[N], lma[N], rma[N], stk[N], tp;
ll f1[N], f2[N], f3[N], f4[N], ans[N], res;
struct Query {
    int id, l, r;
}q[N];
bool cmp(Query x, Query y) {
    if (pos[x.l] == pos[y.l]) return x.r < y.r;
    else return pos[x.l] < pos[y.l];
}
void add_right(int L, int R) {
    int p1 = qry_pmi(L, R);
    int p2 = qry_pma(L, R);
    res += 1ll*(p1 - L + 1) * a[p1] % mod + f1[R] - f1[p1];
    res = (res % mod + mod) % mod;
    res += 1ll*(p2 - L + 1) * a[p2] % mod + f3[R] - f3[p2];
    res = (res % mod + mod) % mod;
}
void add_left(int L, int R) {
    int p1 = qry_pmi(L, R);
    int p2 = qry_pma(L, R);
    res += 1ll*(R - p1 + 1) * a[p1] % mod + f2[L] - f2[p1];
    res = (res % mod + mod) % mod;
    res += 1ll*(R - p2 + 1) * a[p2] % mod + f4[L] - f4[p2];
    res = (res % mod + mod) % mod;
}
void sub_right(int L, int R) {
    int p1 = qry_pmi(L, R);
    int p2 = qry_pma(L, R);
    res -= 1ll*(p1 - L + 1) * a[p1] % mod + f1[R] - f1[p1];
    res = (res % mod + mod) % mod;
    res -= 1ll*(p2 - L + 1) * a[p2] % mod + f3[R] - f3[p2];
    res = (res % mod + mod) % mod;
}
void sub_left(int L, int R) {
    int p1 = qry_pmi(L, R);
    int p2 = qry_pma(L, R);
    res -= 1ll*(R - p1 + 1) * a[p1] % mod + f2[L] - f2[p1];
    res = (res % mod + mod) % mod;
    res -= 1ll*(R - p2 + 1) * a[p2] % mod + f4[L] - f4[p2];
    res = (res % mod + mod) % mod;
}
inline void solve() {
    int T; cin >> T; while (T--) {
        cin >> n >> m;
        init(n);
        int siz = sqrt(n);
        for (int i = 1; i <= n; i++) pos[i] = i / siz;
        for (int i = 1; i <= m; i++) {
            cin >> q[i].l >> q[i].r;
            q[i].id = i;
        }
        sort(q + 1, q + m + 1, cmp);
        tp = 0;
        for (int i = 1; i <= n; i++) {//left samll
            while (tp && a[stk[tp]] > a[i]) tp--;
            if (!tp) lmi[i] = 0;
            else lmi[i] = stk[tp];
            stk[++tp] = i;
        }
        tp = 0;
        for (int i = n; i >= 1; i--) {//right small
            while (tp && a[stk[tp]] > a[i]) tp--;
            if (!tp) rmi[i] = n + 1;
            else rmi[i] = stk[tp];
            stk[++tp] = i;
        }
        tp = 0;
        for (int i = 1; i <= n; i++) {//left big
            while (tp && a[stk[tp]] < a[i]) tp--;
            if (!tp) lma[i] = 0;
            else lma[i] = stk[tp];
            stk[++tp] = i;
        }
        tp = 0;
        for (int i = n; i >= 1; i--) {//right big
            while (tp && a[stk[tp]] < a[i]) tp--;
            if (!tp) rma[i] = n + 1;
            else rma[i] = stk[tp];
            stk[++tp] = i;
        }
        for (int i = 1; i <= n; i++) f1[i] = (f1[lmi[i]] + 1ll * (i - lmi[i]) * a[i] % mod) % mod;
        for (int i = n; i >= 1; i--) f2[i] = (f2[rmi[i]] + 1ll * (rmi[i] - i) * a[i] % mod) % mod;
        for (int i = 1; i <= n; i++) f3[i] = (f3[lma[i]] + 1ll * (i - lma[i]) * a[i] % mod) % mod;
        for (int i = n; i >= 1; i--) f4[i] = (f4[rma[i]] + 1ll * (rma[i] - i) * a[i] % mod) % mod;

        int L = 1, R = 0;
        res = 0;
        for (int i = 1; i <= m; i++) {
            while (q[i].l < L) add_left(--L, R);
            while (q[i].r > R) add_right(L, ++R);
            while (q[i].l > L) sub_left(L++, R);
            while (q[i].r < R) sub_right(L, R--);
            int len = R - L + 1;
            ans[q[i].id] = res * ksm(1ll*len*(len+1) % mod, mod-2) % mod;
        }
        for (int i = 1; i <= m; i++) printf("%lld\n", (ans[i] + mod) % mod);
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值