• 【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】


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

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

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

    所以我还是用了俩...

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

    #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(nsqrt{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
    ", Ans[i]);
        return 0;
    }

     

    感觉这种题就算让我再做一次,也写不出来...重载什么的简直太难记了aaa!!

    对于第一个询问,直接分别处理每行和每列就行了,每行就直接加,每列用差分处理。

    如何查找联通块数量?

    分别处理两种情况:

    1)与下边相交对于上面的矩形,查找它下一排最后一个与它相交的矩形,向前枚举直到不相交,把相交的矩形连边。

    2)与右边相交对于左边的矩形,查找它右边与它相交的所有矩形,连边。

    以上操作用二分实现。注意的是,因为我们建边是在每排的基础上(因为查询的是排),所以第一种应该建在下面那排,第二种应该建在两个矩形上边界的排取max。(查询前缀时才能保证合法)

    stl(vector简直tql!QAQ)

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    int ans2[100005];
    LL ans1[100005], sum2[100005], sum1[100005];
    
    struct Data {
        int lx, ly, rx, ry;
        Data(int lx = 0, int ly = 0, int rx = 0, int ry = 0) :
            lx(lx), ly(ly), rx(rx), ry(ry) { }
    } A[100005];
    
    struct Node {
        int id, l, r;
        Node(int id = 0, int l = 0, int r = 0) :
            id(id), l(l), r(r) { }
    };
    
    vector < Node > row[100005], col[100005];
    bool operator < (const Node &a, const Node &b) {
        return a.l < b.l || (a.l == b.l && a.r < b.r);
    }
    
    vector < pair < int , int > > G[1000005];
    
    int root[100005], edge, num;
    int find(int x) {
        if(root[x] != x)    root[x] = find(root[x]);
        return root[x];
    }
    
    void merge(int x, int y) {
        x = find(x); y = find(y);
        if(x != y)    root[x] = y, ++ edge;
    }
    
    int main() {
        freopen("building.in", "r", stdin);
        freopen("building.out", "w", stdout);
        int opt;
        scanf("%d", &opt);
        int n, m, k, p;
        scanf("%d%d%d%d", &n, &m, &k, &p);
        for(int i = 1; i <= k; i ++) {
            int lx, ly, rx, ry;
            scanf("%d%d%d%d", &lx, &ly, &rx, &ry);
            A[i] = Data(lx, ly, rx, ry);
            row[lx].push_back(Node(i, ly, ry));
            col[ly].push_back(Node(i, lx, rx));
            if(lx == rx)    sum1[lx] += (ry - ly + 1);
            else sum2[lx] ++, sum2[rx + 1] --;
        }
        for(int i = 1; i <= n; i ++)    sort(row[i].begin(), row[i].end());
        for(int i = 1; i <= m; i ++)    sort(col[i].begin(), col[i].end());
        for(int i = 1; i <= k; i ++) {
            int down = A[i].rx + 1;
            if(down <= n && row[down].size()) {
                int p = upper_bound(row[down].begin(), row[down].end(), Node(0, A[i].ry, m + 1)) - row[down].begin() - 1;
                for(; p >= 0 && row[down][p].r >= A[i].ly; p --)
                    G[down].push_back(make_pair(i, row[down][p].id));
            }
            int right = A[i].ry + 1;
            if(right <= m && col[right].size()) {
                if(right < 0)    return 0; 
                int p = upper_bound(col[right].begin(), col[right].end(), Node(0, A[i].rx, n + 1)) - col[right].begin() - 1;
                for(; p >= 0 && col[right][p].r >= A[i].lx; p --)
                    G[max(A[i].lx, A[col[right][p].id].lx)].push_back(make_pair(i, col[right][p].id));
            }
        }
        for(int i = 1; i <= n; i ++)    sum2[i] += sum2[i-1];
        for(int i = 1; i <= n; i ++) {
            sum2[i] += sum2[i-1];
            sum1[i] += sum1[i-1];
            ans1[i] = sum1[i] + sum2[i];
        }
        for(int i = 1; i <= k; i ++)    root[i] = i;
        for(int i = 1; i <= n; i ++) {
            num += row[i].size();
            for(int j = 0; j < G[i].size(); j ++)    merge(G[i][j].first, G[i][j].second);
            ans2[i] = num - edge;
        }
        while(p --) {
            int u, v;
            scanf("%d%d", &u, &v);
            if(u)    printf("%d
    ", ans2[v]);
            else    printf("%lld
    ", ans1[v]);
        }
        return 0;
    }
  • 相关阅读:
    SVN还原项目到某一版本(转)
    C# Web Service 不使用服务引用直接调用方法(转)
    动态调用webservice时 ServiceDescriptionImporter类在vs2010无法引用的解决方法 (转)
    log4net示例2-日志输入存入Access(转)
    C# log4net 配置及使用详解--日志保存到文件和Access(转)
    未能解析引用的程序集......因为它对不在当前目标框架“.NETFramework,Version=v4.0,Profile=Client”中的 (转)
    Hello log4net——做一个实用好用的log4net的demo(转)
    JS移动客户端--触屏滑动事件
    js生成二维码实例
    触屏版类似刷新页面文本框获取焦点的同时弹出手机键盘的做法
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9773027.html
Copyright © 2020-2023  润新知