zoukankan      html  css  js  c++  java
  • 【题录】ICPC2020 小米邀请赛决赛

    B.

    分治。每次分治一个区间的时候统计所有跨过左右区间的区间对答案的贡献。令一个区间的左右端点分别为 a, b。那么这个区间的答案为 max(m[a], m[b], f[a] + f[b])。其中 m[x] 为 x 到中点的最大子段和,f[x] 为 x 到中点的最大前缀和。使用两个指针向两边扫,每次挪动一个指针 a 的时候统计所有区间 [a, x] (x 属于 [mid + 1, b)) 的答案。这样每个区间一定会被统计到一次。每次选择挪动 m[x] 更小的指针 x ,可以保证 m[x] > m[y] (以 x 在左侧为例,y 属于 [mid + 1, b))。

    #include <bits/stdc++.h>
    using namespace std;
    #define ULL unsigned long long
    #define LL long long
    #define maxn 250000
    #define INF 1ll << 60
    LL n, a[maxn], lsum[maxn], rsum[maxn], lmax[maxn], rmax[maxn];
    ULL lsums[maxn], rsums[maxn];
    
    int Getl(int l, int r, LL t) {
        if(lsum[l] < t) return l - 1;
        while(l < r) {
            int mid = (l + r) >> 1;
            if(mid + 1 <= r) mid += 1;
            if(lsum[mid] >= t) l = mid;
            else r = mid - 1;
        }
        return l;
    }
    
    int Getr(int l, int r, LL t) {
        if(rsum[r] < t) return r + 1;
        while(l < r) {
            int mid = (l + r) >> 1;
            if(rsum[mid] >= t) r = mid;
            else l = mid + 1;
        }
        return l;
    }
    
    ULL Divide(int l, int r) {
        if(l == r) return a[l];
        int mid = (l + r) >> 1;
        ULL ans = Divide(l, mid) + Divide(mid + 1, r);
        lmax[mid + 1] = -INF; lsum[mid + 1] = -INF;  lsums[mid + 1] = 0;
        LL sum = 0, maxs = 0;
        for(int i = mid; i >= l; i --) {
            maxs += a[i]; 
            lmax[i] = max(lmax[i + 1], maxs);
            maxs = max(0ll, maxs);
            sum += a[i];
            lsum[i] = max(lsum[i + 1], sum);
            lsums[i] = lsums[i + 1] + lsum[i];
        }
        sum = 0, maxs = 0;
        rmax[mid] = -INF, rsum[mid] = -INF; rsums[mid] = 0;
        for(int i = mid + 1; i <= r; i ++) {
            maxs += a[i]; 
            rmax[i] = max(rmax[i - 1], maxs);
            maxs = max(0ll, maxs);
            sum += a[i];
            rsum[i] = max(rsum[i - 1], sum);
            rsums[i] = rsums[i - 1] + rsum[i];
        }
        int ll = mid, rr = mid + 1;
        ULL ans1 = 0; 
        while(ll >= l || rr <= r) {
            if(rr > r || (ll >= l && lmax[ll] <= rmax[rr])) {
                int p = Getr(mid + 1, rr - 1, lmax[ll] - lsum[ll]);
                if(mid + 1 <= rr - 1) ans1 += (p - 1 - mid) * lmax[ll] + (rr - p) * lsum[ll] + rsums[rr - 1] - rsums[p - 1];
              ll --;
            }
            else if(ll < l || (rr <= r && rmax[rr] <= lmax[ll])) {
                int p = Getl(ll + 1, mid, rmax[rr] - rsum[rr]);
                if(ll + 1 <= mid) ans1 += (mid - p) * rmax[rr] + (p - ll) * rsum[rr] + lsums[ll + 1] - lsums[p + 1];
                rr ++;
            }
        }
        ans += ans1;
        return ans;
    }
    
    int main() {
        ios::sync_with_stdio(0); cin.tie(0);
        cin >> n;
        for(int i = 1; i <= n; i ++) cin >> a[i];
        cout << Divide(1, n) << endl;
        return 0;
    }

    G.

    状压,每次枚举子集 S 为拓扑序最底层的点,判断是否满足条件。满足条件则计入答案。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 200000
    int n, m, bits[maxn], mark[maxn], rec[maxn];
    LL f[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct edge {
        int cnp = 1, to[maxn], last[maxn], head[maxn];
        void add(int u, int v) {
            to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
            to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
        }
    }E;
    
    int main() {
        n = read(), m = read();
        for(int i = 1; i <= m; i ++) {
            int x = read(), y = read();
            E.add(x, y);
        }
        bits[0] = 1;
        for(int i = 1; i < n; i ++) bits[i] = bits[i - 1] << 1;
        for(int i = 0; i < bits[n]; i ++) {
            for(int j = 1; j <= m; j ++)
                if(bits[j - 1] & i) {
                    for(int k = E.head[j]; k; k = E.last[k]) {
                        int v = E.to[k];
                        if(bits[v - 1] & i) mark[i] = 0;
                        else rec[i] |= bits[v - 1]; 
                    } 
                }
        }
        f[0] = 1;
        for(int S = 1; i < bits[n]; i ++) 
            for(int S1 = (S - 1) & S; S1; S1 = (S1 - 1) & S) {
                if(!mark[S1]) continue;
                S2 = S ^ S1;
                if((S2 | rec[S1]) > rec[S1]) continue;
                f[S] += f[S2];
            }
        printf("%lld
    ", f[bits[n] - 1]);
        return 0;
    }

    J.

    书本不会掉下去的条件即为任何一本书,它上面的所有书的重心落在这本书上(对桌子也一样)。考虑让其中伸出去的书最远,要么是像例1一样一本一本的往外面叠,要么像例2一样用一些书压住另一本,再让这一本尽可能的往外伸。还是用状压,枚举最下面的一本书是哪一本,分以上两种情况讨论一下即可。

    #include <bits/stdc++.h>
    using namespace std;
    #define db double
    #define maxn 3000000
    int n, l[maxn], bits[maxn], w[maxn], m[maxn];
    db f[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    db DP(int S) {
        if(f[S] >= 0) return f[S];
        if(!S) return f[S] = 0;
        for(int i = 1; i <= n; i ++) {
            if(!(bits[i - 1] & S)) continue;
            int S1 = S ^ bits[i - 1];
            db L = DP(S1);
            db l1 = (db) l[i] / 2 - (m[S1] * ((db) l[i] / 2) / m[S]);
            f[S] = max(f[S], l1 + L);
            l1 = (db) m[S1] * ((db) l[i] / 2) / m[S] + (db) l[i] / 2;
            f[S] = max(f[S], l1);
        }
        return f[S];
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) l[i] = read();
        for(int i = 1; i <= n; i ++) w[i] = read();
        bits[0] = 1;
        for(int i = 1; i <= n; i ++) bits[i] = bits[i - 1] << 1;
        for(int i = 0; i < bits[n]; i ++) f[i] = -1;
        for(int i = 0; i < bits[n]; i ++) 
            for(int j = 1; j <= n; j ++)
                if(bits[j - 1] & i) m[i] += w[j];
        printf("%.10f
    ", DP(bits[n] - 1));
        return 0;
    }
  • 相关阅读:
    Hdu 1429 胜利大逃亡(续) (bfs+状态压缩)
    Vijos 1456 最小总代价 (状压dp)
    洛谷 P1313 计算系数 (二项式定理)
    洛谷 P1134 阶乘问题
    EINTR错误
    TCP和UDP协议的应用/参数查看
    BAT面经
    高级环境编程要看的
    UDP丢包和无序 问题的解决方法
    tcp/ip
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/14228843.html
Copyright © 2011-2022 走看看