• 【cf1307E】E. Cow and Treats(组合数学)


    传送门

    题意:
    现有(n,nleq 5000)块草皮,每块草皮都有一个美味度(s_i)
    现有(m,mleq 5000)头牛,每头牛有两个属性(f_i h_i),分别表示这头牛只吃美味度为(f_i)的草皮以及要吃(h_i)块这样的草皮。
    每头牛在吃饱过后就会原地打盹,之后的牛都不能从那里跨过去。我们称一头打盹的牛为“幸福的牛”。
    现在可以安排这(m)头牛从左边出发或者从右边出发,现在要使得“幸福的牛”数量最多,同时统计使得数量最多的方案数。

    思路:
    容易发现,现在要吃某一种美味度的草皮,从一侧出发的牛不能超过一头。
    然后还有一个重要的性质:

    • 假设现在确定了边界(i),即从左边出发不能超过(i)这个位置,从右边出发不能超过(i)这个位置。那么一定存在一种方案,使得左侧/右侧的草皮能吃的都吃完。

    也就是说,我们不需要考虑牛从两侧出发的顺序,即,我们对于左右两侧同一种美味度的草皮,可以单独考虑其贡献:

    • 若对于美味度为(i)的草皮,左边有(l_i)块,右边为(r_i)块,有(c_{i1})头牛吃的草皮数不超过(l_i),有(c_{i2})头牛吃的草皮数不超过(r_i),不妨(c_{i1}<c_{i2}),那么此时方案数为(c_{i1}cdot (c_{i2}-1))

    就有一个暴力的算法:我们依次每个位置,假设当前枚举的美味度为(s_i),那么对于其它美味度的贡献可以直接像上述来计算,对于(s_i)来说则只有(r_{pos_{now}})种情况。若这里直接将(s_i)按照上述那样来计算,则会计算相同的情况。
    这样的话时间复杂度为(O(n^2))或者(O(n^2logn)),也能够通过此题。

    这里的话可以优化时间复杂度到(O(n))
    我们只需要维护(tot_{asleep},tot_{ways}),那么枚举每个位置时,直接减去这种美味度的贡献即可。最后统计完答案了再加回来。这样的话就去掉了一层循环。
    代码可能有些细节:

    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/18 15:29:15
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5000 + 5, MOD = 1e9 + 7;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
    
    int inv(int x) {
        return qpow(x, MOD - 2);   
    }
    
    int n, m;
    int a[N];
    int f[N], h[N];
    int x[N], y[N];
    int l[N], r[N];
    vector <int> v[N];
    
    void run(){
        cin >> n >> m;
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
            ++r[a[i]];
        }
        for(int i = 1; i <= m; i++) {
            cin >> f[i] >> h[i];   
            v[f[i]].push_back(h[i]);
        }
        for(int i = 1; i <= n; i++) sort(all(v[i]));
        pii ans(0, 0);
        auto upd = [&](int x, int y) {
            if(x > ans.fi) ans = MP(x, 0);
            if(x == ans.fi) ans.se = (ans.se + y) % MOD;
        };
        auto calc = [&](int i) {
            int a = upper_bound(all(v[i]), l[i]) - v[i].begin();
            int b = upper_bound(all(v[i]), r[i]) - v[i].begin();
            if(a > b) swap(a, b);
            int cnt1 = 1ll * a * (b - 1) % MOD, cnt2 = a + b;
            if(cnt1 > 0) {
                x[i] = 2;
                y[i] = cnt1;
            } else if(cnt2 > 0) {
                x[i] = 1;
                y[i] = cnt2;
            } else {
                x[i] = 0;
                y[i] = 1;
            }
        };
        int tx = 0, ty = 1;
        for(int i = 1; i <= n; i++) {
            calc(i);
            tx += x[i];
            ty = 1ll * ty * y[i] % MOD;
        }
        upd(tx, ty);
        for(int i = 1; i <= n; i++) {
            int now = a[i];
            tx -= x[now];
            ty = 1ll * ty * inv(y[now]) % MOD;
            ++l[now], --r[now];
            if(binary_search(all(v[now]), l[now])) {
                int t = upper_bound(all(v[now]), r[now]) - v[now].begin();
                if(r[now] >= l[now]) --t;
                if(t > 0) {
                    x[now] = 2;
                    y[now] = t;
                } else {
                    x[now] = y[now] = 1;   
                }
                int nx = tx + x[now], ny = 1ll * ty * y[now] % MOD;
                upd(nx, ny);
            }
            calc(now);
            tx += x[now];
            ty = 1ll * ty * y[now] % MOD;
        }
        cout << ans.fi << ' ' << ans.se << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    
  • 相关阅读:
    [转]Article: Invalid cross-thread operations
    【转】20余个国外免费英文电子书下载网站
    [转]推荐国外SQL Server学习网站
    【转】C#中的序列化和反序列化是什么、有什么作用、使用方法详解
    [转]How I explained OOD to my wife
    [转]How I explained Design Patterns to my wife: Part 1
    git和gitee的安装、上传和下载(一)
    【工作备忘】python读取oracle写入csv遇到的问题
    处理基地营地 html的python环境设置 (给同事参考的)
    爬虫scrapy-begin
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12326887.html
Copyright © 2020-2023  润新知