【10.11校内测试】【优先队列(反悔贪心)】【莫队】

上次做过类似的题,原来这道还要简单些??

上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列)。

这道题实际上用一个就够了???但是不好理解!!

所以我还是用了俩...

和之前那道题不同的是,如果我选择了反悔,之前第二个队列的队头就完全没有用了,但是我们可以选择重新买它,所以把它重新放到第一个队列。

#include<bits/stdc++.h>
using namespace std;

priority_queue < int, vector < int >, greater < int > > q1, q2;

int n, a[100005];
long long ans;

int main() {
    freopen("trade.in", "r", stdin);
    freopen("trade.out", "w", stdout);
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)    scanf("%d", &a[i]);
    for(int i = 1; i <= n; i ++) {
        int x1, x2, r1 = 0, r2 = 0;
        if(!q1.empty())    {
            x1 = q1.top(); if(a[i] - x1 > 0)    r1 = a[i] - x1;
        }
        if(!q2.empty())    {
            x2 = q2.top(); if(a[i] - x2 > 0)    r2 = a[i] - x2;
        }
        if(r1 >= r2 && r1) {
            q1.pop(); q2.push(a[i]); ans += r1;
        } else if(r2 > r1 && r2 ) {
            q2.pop(); q2.push(a[i]); q1.push(x2); ans += r2;
        } else q1.push(a[i]);
    }
    printf("%lld", ans);
    return 0;
}

这道题乍一看是推公式$O(1)$的数论??经$yuli$dalao考场上一个多小时的测试发现没有这样的式子....

所以$zc$dalao通过研究打表发现了正解!其实是莫队!

???

首先我们也来打一下表....发现了两个递推式:$S_n^m=S_n^{m-1}+C_n^m$和$S_n^m=2S_{n-1}^m-C_{n-1}^m$,我们可以把$[n,m]$看成一个区间来进行离线莫队转移,复杂度$O(n\sqrt{n})$。

#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
using namespace std;

int blo[100005];

struct Node {
    int n, m, id;
} qus[100005];
bool cmp(Node a, Node b) { if(blo[a.m] == blo[b.m]) return a.n < b.n; return a.m < b.m; }

LL fac[100005], inv[100005];
LL C(int n, int m) {
    if(m > n)    return 0;
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

LL mpow(LL a, LL b) {
    LL ans = 1;
    for(; b; b >>= 1, a = a * a % mod)
        if(b & 1)    ans = ans * a % mod;
    return ans;
}

void init() {
    fac[0] = 1; inv[0] = 1, inv[1] = 1;
    for(int i = 1; i <= 100005; i ++)
        fac[i] = fac[i - 1] * i % mod;
    for(int i = 2; i <= 100005; i ++)
        inv[i] = mpow(fac[i], mod - 2);
    for(int i = 1; i <= 100005; i ++)    blo[i] = i/300 + 1;
}

int Ans[100005];
int main() {
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);
    int id;
    scanf("%d", &id);
    init();
    int T;
    scanf("%d", &T);
    for(int i = 1; i <= T; i ++)
        scanf("%d%d", &qus[i].n, &qus[i].m), qus[i].id = i;
    sort(qus + 1, qus + 1 + T, cmp);
    
    int n = qus[1].n, m = qus[1].m; LL ans = 0;
    for(int i = 0; i <= m; i ++)    ans = (ans + C(n, i)) % mod;
    Ans[qus[1].id] = ans;
    for(int i = 2; i <= T; i ++) {
        while(qus[i].m < m) {
            ans = (ans - C(n, m) + mod) % mod;
            m --;
        }
        while(qus[i].n > n) {
            ans = (2LL * ans % mod - C(n, m) + mod) % mod;
            n ++;
        }
        while(qus[i].m > m) {
            m ++;
            ans = (ans + C(n, m)) % mod;
        }
        while(qus[i].n < n) {
            n --;
            ans = 1LL * (ans + C(n, m)) * inv[2] % mod;
        }
        Ans[qus[i].id] = ans;
    }
    for(int i = 1; i <= T; i ++)    printf("%d\n", Ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wans-caesar-02111007/p/9773027.html
今日推荐