zoukankan      html  css  js  c++  java
  • 2020.1.15考试总结

    T1
    01分数规划
    很明显我们需要的区间最大值和最小值在区间两端,因为有L的限制,所以我们可以先做一遍长度为L的滑动窗口。
    问题判定的转化,设我们二分的值是v:
    (displaystyle frac{A[r]-A[l]}{r-l+k} > v)
    (displaystyle (A[r]-rv)-(A[l]-lv) > kv)
    再用一个单调队列维护一下就好了。

    #include <iostream>
    #include <cstdio>
    #define LL long long
    #define DB double
    using namespace std;
    int T, n, k, L, R, head1 = 1, tail1, head2 = 1, tail2;
    DB ans;
    const int N = 50010;
    const DB eps = 1e-7;
    int a[N], q1[N], q2[N]; /*小 大*/
    DB b[N];
    inline int read() 
    {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
        return x * f;
    }
    int dd(DB mid) 
    {
        head1 = head2 = 1; tail1 = tail2 = 0;
        for (int i = L; i <= n; ++i) 
        {
            while (head1 <= tail1 && b[i - L + 1] <= b[q1[tail1]])--tail1;
            q1[++tail1] = i - L + 1;
            while (head1 <= tail1 && i - q1[head1] + 1 > R)++head1;
            if (b[i] - b[q1[head1]] >= mid * k)return 1;
        }
        return 0;
    }
    int check(DB mid) 
    {
        for (int i = 1; i <= n; ++i)b[i] = a[i] - mid * i;    if (dd(mid))return 1;
        for (int i = 1; i <= n; ++i)b[i] = a[n - i + 1] - mid * i; if (dd(mid))return 1;
        return 0;
    }
    void solve() 
    {
        DB l, r, mid;
        head1 = head2 = 1; tail1 = tail2 = 0;
        for (int i = 1; i <= n; ++i) 
        {
            while (head1 <= tail1 && a[i] <= a[q1[tail1]])--tail1;
            while (head2 <= tail2 && a[i] >= a[q2[tail2]])--tail2;
            q1[++tail1] = i; q2[++tail2] = i;
            while (head1 <= tail1 && i - q1[head1] + 1 > L)++head1;
            while (head2 <= tail2 && i - q2[head2] + 1 > L)++head2;
            ans = max(ans, (DB)(a[q2[head2]] - a[q1[head1]]) / (L - 1 + k));
        }
        l = 0; r = 1000;
        while (r - l > eps) 
        {
            mid = (l + r) / 2;
            if (check(mid))l = mid;
            else r = mid;
        }
        printf("%.4f
    ", max(ans, mid));
    }
    int main() 
    {
        cin >> T;
        while (T--) 
        {
            n = read(); k = read(); L = read(); R = read(); ans = 0;
            for (int i = 1; i <= n; ++i)a[i] = read();
            solve();
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
    

    T2 给定一个长度为 (n) 的序列 (a_i), 求有多少个区间的和 (\%k) 等于区间的最小值。((n le 2 imes 10^5))

    看到这类题首先想到每一个值的贡献,确定左右边界就用单调栈。
    然后左右边界那边小就枚举哪一边,类似于启发式合并。
    时间复杂度(O(nlog^2n))
    关于边界的细节处理比较复杂,需要注意。

    #include <iostream>
    #include <cstdio>
    #define int long long
    #define LL long long
    using namespace std;
    int n, k, ans, top, cnt;
    const int N = 200010;
    int a[N], zhan[N], l[N], r[N], s[N], root[N];
    int sum[N * 100], lson[N * 100], rson[N * 100];
    inline int read() 
    {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
        return x * f;
    }
    void change(int pre, int &k, int l, int r, int pos, int val) 
    {
        if (!k)k = ++cnt; sum[k] = sum[pre] + val;
        if (l == r)return; int mid = (l + r) >> 1;
        if (pos <= mid)rson[k] = rson[pre], change(lson[pre], lson[k], l, mid, pos, val);
        else lson[k] = lson[pre], change(rson[pre], rson[k], mid + 1, r, pos, val);
    }
    int ask(int pre, int k, int l, int r, int pos) 
    {
        if (l == r)return sum[k] - sum[pre];
        int mid = (l + r) >> 1;
        if (pos <= mid)return ask(lson[pre], lson[k], l, mid, pos);
        else return ask(rson[pre], rson[k], mid + 1, r, pos);
    }
    signed main() 
    {
        cin >> n >> k;
        change(root[0], root[1], 0, k, 0, 1);
        for (int i = 2; i <= n + 1; ++i)a[i] = read(), s[i] = (a[i] + s[i - 1]) % k, change(root[i - 1], root[i], 0, k, s[i], 1);
        for (int i = 2; i <= n + 1; ++i) 
        {
            while (top && a[i] <= a[zhan[top]])r[zhan[top--]] = i;
            l[i] = zhan[top]; zhan[++top] = i;
        }
        for (int i = 2; i <= n + 1; ++i) 
        {
            if (!l[i])l[i] = 1;
            if (!r[i])r[i] = n + 2;
        }
        for (int i = 2; i <= n + 1; ++i) 
        {
            if (a[i] >= k)continue;
            if (i - l[i] < r[i] - i)for (int j = l[i] + 1; j <= i; ++j)ans += ask(root[i - 1], root[r[i] - 1], 0, k, (s[j - 1] + a[i]) % k);
            else for (int j = i; j <= r[i] - 1; ++j)ans += ask(root[l[i] - 1], root[i - 1], 0, k, (s[j] - a[i] + k) % k);
        }
        cout << ans;
        fclose(stdin); fclose(stdout);
        return 0;
    }
    

    T3 给定你n,m,求(displaystyle sum_{i=1}^ni^mm^i) ((mod) (10^9+7)) ((n le 10^9 ,m le 1000))

    老师说是套路题...
    我们设(displaystyle f(j)=sum_{i=1}^ni^jm^i)
    那么

    [egin{aligned} displaystyle (m-1)f(j)=&sum_{i=1}^n i^j m^{i+1} - sum_{i=1}^ni^jm^i\ displaystyle (m-1)f(j)=&sum_{i=2}^{n+1} (i-1)^j m^{i} - sum_{i=1}^{n}i^{j}m^{i}\ displaystyle (m-1)f(j)=&sum_{i=1}^{n} (i-1)^j m^{i} - sum_{i=1}^{n}i^{j}m^{i}+n^{j}m^{n+1}\ displaystyle (m-1)f(j)=&sum_{i=1}^{n}((i-1)^j - i^{j})m^{i}+n^{j}m^{n+1}\ displaystyle (m-1)f(j)=&sum_{i=1}^{n}(sum_{k=0}^{j}C_{j}^{k}i^{k}(-1)^{j-k}-i^j)m^{i}+n^{j}m^{n+1}\ displaystyle (m-1)f(j)=&sum_{i=1}^{n}(sum_{k=0}^{j-1}C_{j}^{k}i^{k}(-1)^{j-k})m^{i}+n^{j}m^{n+1}\ displaystyle (m-1)f(j)=&sum_{k=0}^{j-1}C_{j}^{k}(-1)^{j-k}(sum_{i=1}^{n}i^{k}m^{i})+n^{j}m^{n+1}\ displaystyle (m-1)f(j)=&sum_{k=0}^{j-1}C_{j}^{k}(-1)^{j-k}f(k)+n^{j}m^{n+1}\ displaystyle f(j)=&frac{displaystyle sum_{k=0}^{j-1}C_{j}^{k}(-1)^{j-k}f(k)+n^{j}m^{n+1}}{m-1}\ end{aligned} ]

    然后就是一个和(n)无关的(O(m^2))的递推式了.

    注意(f(0))需要单独求。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define int long long
    #define LL long long
    using namespace std;
    int n, m;
    const int mod = 1e9 + 7, N = 1005;
    LL ans;
    LL jc[N], inv[N], F[1005];
    inline int read() 
    {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
        return x * f;
    }
    LL ksm(LL a, LL b, LL mod) 
    {
        LL res = 1;
        for (; b; b >>= 1, a = a * a % mod)
            if (b & 1)res = res * a % mod;
        return res;
    }
    LL C(int n, int m) {return jc[n] * inv[m] % mod * inv[n - m] % mod;}
    LL f(int k) 
    {
        if (F[k] != -1)return F[k];
        LL res = 0;
        for (int j = 0; j <= k - 1; ++j)(res += ((k - j) & 1 ? -1 : 1) * C(k, j) % mod * f(j)) %= mod;
        (res += ksm(n, k, mod) * ksm(m, n + 1, mod) % mod) %= mod;
        return F[k] = res * ksm(m - 1, mod - 2, mod) % mod;
    }
    signed main() 
    {
        memset(F, -1, sizeof(F));
        cin >> n >> m;
        jc[0] = jc[1] = inv[0] = inv[1] = 1;
        for (int i = 2; i <= 1000; ++i)jc[i] = jc[i - 1] * i % mod;
        inv[1000] = ksm(jc[1000], mod - 2, mod);
        for (int i = 999; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
        F[0] = (ksm(m, n + 1, mod) - m) * ksm(m - 1, mod - 2, mod) % mod;
        cout << (f(m) % mod + mod) % mod;
        fclose(stdin); fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    centos6.4下搭建Lampp
    lampp环境部署bugfree3.0.4
    ftp使用踩坑
    redis故障处理
    程序设计语言发展回顾与展望
    那些相见恨晚的 JavaScript 技巧
    我的七个建议
    让UNION与ORDER BY并存于SQL语句当中
    使用SQL语句创建登录名,并为指定数据库分配制定权限
    Linux操作系统菜鸟变成高手的十个建议
  • 原文地址:https://www.cnblogs.com/wljss/p/12197239.html
Copyright © 2011-2022 走看看