zoukankan      html  css  js  c++  java
  • 「NOI.AC」NOI挑战赛第二场

    博主由于暂时退役失败又回来更博了。但是退役也快了。

    亏死了,要不是 T2 数组开小了就 rk1 了。

    A. 黑白沙漠

    然而我并不会,先咕了

    B. 荒野聚餐

    不妨设 (a_i) 表示雄性鸟人 (i) 的花费,(b_i) 表示雌性鸟人 (i) 的花费。列一下 LP:

    [egin{aligned} ext{minimize } S+sum_{i=1}^n a_i+b_i\ ext{s.t.} egin{cases} a_i+b_j+frac{S}{C} geq w_{i,j} ,forall i,j in [1,n]\ a_i geq 0,b_i geq 0,S geq 0 end{cases} end{aligned} ]

    这个限制不好看 于是考虑它的对偶问题:

    [egin{aligned} ext{maximize } sum_{i=1}^n sum_{j=1}^n w_{i,j}c_{i,j}\ ext{s.t.} egin{cases} sum_{j=1}^n c_{i,j} leq 1 ,forall i in [1,n]\ sum_{j=1}^n c_{j,i} leq 1 ,forall i in [1,n]\ sum_{i=1}^n sum_{j=1}^n c_{i,j} leq C end{cases} end{aligned} ]

    发现是个网络流问题(你可以理解成 (n imes n) 的棋盘,每个点有一个颜色,每行每列至多只能选一个,所以就是大小为 (C) 的最大权匹配问题)

    写个费用流能 77 分,题解上说写要求 KM 算法,我不会(你这个菜怎么啥都不会啊)

    C. 火星在住

    不妨设 (f_i) 表示选 (i) 条边的答案,发现可以建出费用流,并且要求流量(=i),所以 (f) 是凸的。

    考虑朴素dp:(f_{v,i,0/1}) (v) 这个点选了 (i) 条边,这个点有没有被选的答案。转移的时候是做的 ((max,+)) 卷积,由于是凸的,可以闵科夫斯基和合并凸包做到单次 (O(n)),于是你有了一个 (O(n^2)) 的做法。

    链的做法有一个比较神奇的做法:每次从堆中取出最大的,设代价为 (w) ,设它左右两边点的代价为(w_l,w_r),那么把 (w_l+w_r-w) 扔进堆里,并且删掉 (l,r) 。这样其实是部分模拟了费用流,但是难以拓展到树上。

    可以快速合并两个数组了,我们考虑使用链分治。大概就是你先对树重链剖分,对于重链先求出每个重链上的点的 dp 数组,然后再重链上分治合并。求每个点的 dp 数组的时候有可能需要合并若干个轻儿子的 dp 数组,也需要分治合并。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <climits>
    #include <cstdlib>
    #include <cstdio>
    #include <bitset>
    #include <cassert>
    #include <vector>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    #define int LL
    const int MAXN = 2e5 + 5;
    
    struct Edge{
        int to,w,nxt;
    }e[MAXN<<1];
    int head[MAXN],cnt;
    
    inline void add(int u,int v,int w){
        e[++cnt] = (Edge){v,w,head[u]};head[u] = cnt;
        e[++cnt] = (Edge){u,w,head[v]};head[v] = cnt;
    }
    
    int val[MAXN],sz[MAXN],son[MAXN],tp[MAXN],fa[MAXN],n;
    
    inline void dfs1(int v){
        sz[v] = 1;
        for(int i = head[v];i;i = e[i].nxt){
            if(e[i].to == fa[v]) continue;
            fa[e[i].to] = v;val[e[i].to] = e[i].w;dfs1(e[i].to);
            sz[v] += sz[e[i].to];
            if(sz[son[v]] < sz[e[i].to]) son[v] = e[i].to;
        }
    }
    
    inline void dfs2(int v,int tp){
        ::tp[v] = tp;
        if(son[v]) dfs2(son[v],tp);
        for(int i = head[v];i;i = e[i].nxt){
            if(e[i].to == fa[v] || e[i].to == son[v]) continue;
            dfs2(e[i].to,e[i].to);
        }
    }
    
    inline void upmax(int &x,int y){
        if(x < y) x = y;
    }
    
    struct Poly{
        std::vector<int> x;
        inline int& operator [] (const int &n){return x[n];}
        inline int deg(){return (int)x.size()-1;}
        inline void ext(const int &n){x.resize(n+1);}
        Poly(int n=-1){ext(n);FOR(i,0,n) x[i] = -1e18;}
        inline void print(){
            FOR(i,0,deg()) printf("%lld ",x[i]);puts("");
        }
        friend Poly operator + (Poly A,Poly B){
            Poly res(A.deg()+B.deg());
            int i = 0,j = 0;
            while(i <= A.deg() && j <= B.deg()){
                upmax(res[i+j],A[i]+B[j]);
                if(i+1 > A.deg() || j+1 > B.deg()) break;
                if(A[i+1]+B[j] >= A[i]+B[j+1]) ++i;
                else ++j;
            }
            FOR(k,i+1,A.deg()) upmax(res[k+j],A[k]+B[j]);
            FOR(k,j+1,B.deg()) upmax(res[i+k],A[i]+B[k]);
            return res;
        }
        friend Poly operator + (Poly A,const int &d){
            A.ext(A.deg()+1);
            ROF(i,A.deg(),1) A[i] = A[i-1]+d;
            A[0] = -1e18;
            return A;
        }
    };
    
    inline void upmax(Poly &A,Poly B){
    //    DEBUG(1);
        FOR(i,0,B.deg()){
            if(i > A.deg()) A.x.pb(B[i]);
            else upmax(A[i],B[i]);
        }
    }
    
    struct Node{
        Poly f[2][2];
    };
    bool xxx;
    inline Node merge(Node A,Node B,int w,bool flagl=0,bool flagr=0){
        Node res;
        FOR(i,0,1){
            FOR(j,0,1){
                upmax(res.f[i][j],A.f[i][0]+B.f[1][j]);
                //if(xxx) res.f[0][0].print();
                upmax(res.f[i][j],A.f[i][1]+B.f[0][j]);
                //if(xxx) res.f[0][0].print();
                upmax(res.f[flagl|i][flagr|j],(A.f[i][0]+B.f[0][j])+w);
                upmax(res.f[i][j],A.f[i][0]+B.f[0][j]);
                upmax(res.f[i][j],A.f[i][1]+B.f[1][j]);
            }
        }
        return res;
    }
    
    Poly g[MAXN][2];
    
    inline Node work(std::vector<int> &chain,int l,int r){
        if(l == r){
            Node res;
            res.f[0][0] = g[chain[l]][0];
            res.f[1][1] = g[chain[l]][1];
            res.f[1][0].x.pb(-1e18);res.f[0][1].x.pb(-1e18);
            return res;
        }
        int mid = (l + r) >> 1;
        Node ll = work(chain,l,mid),rr = work(chain,mid+1,r);
    //    if(l == 0 && r == 2) xxx = 1,DEBUG(1);
        Node t = merge(ll,rr,val[chain[mid+1]],mid-l+1==1,r-mid==1);
        xxx = 0;
        if(l == 0 && r == 2){
    //        DEBUG(l);DEBUG(r);
    //        FOR(i,0,1) FOR(j,0,1) ll.f[i][j].print();
    //        puts("");
    //        FOR(i,0,1) FOR(j,0,1) rr.f[i][j].print();
    //        puts("");
    //        FOR(i,0,1) FOR(j,0,1) t.f[i][j].print();
        }
        return t;
    }
    
    struct NODE{
        Poly f[2];
    };
    
    inline NODE merge(NODE A,NODE B){
        NODE res;
        upmax(res.f[1],A.f[1]+B.f[0]);
        upmax(res.f[1],A.f[0]+B.f[1]);
        upmax(res.f[0],A.f[0]+B.f[0]);
        return res;
    }
    
    inline NODE work2(std::vector<int> &chain,int l,int r){
        if(l > r){
            NODE res;
            res.f[0].x.pb(0);res.f[1].x.pb(-1e18);
            return res;
        }
        if(l == r){
            NODE res;
            res.f[1] = g[chain[l]][0]+val[chain[l]];
            res.f[1][0] = -1e18;
            upmax(res.f[0],g[chain[l]][0]);
            upmax(res.f[0],g[chain[l]][1]);
            return res;
        }
        int mid = (l + r) >> 1;
        return merge(work2(chain,l,mid),work2(chain,mid+1,r));
    }
    
    inline void get1(int);
    inline void get2(int);
    
    inline void get1(int v){
        std::vector<int> chain;
        int now = v;
        while(now) chain.pb(now),now = son[now];
        FOR(i,0,(int)chain.size()-1) get2(chain[i]);
        Node res = work(chain,0,(int)chain.size()-1);
        upmax(g[v][0],res.f[0][0]);upmax(g[v][0],res.f[0][1]);
        upmax(g[v][1],res.f[1][0]);upmax(g[v][1],res.f[1][1]);
    //    if(v == 1) g[v][0].print(),g[v][1].print();
    }
    
    inline void get2(int v){
        g[v][0].x.pb(0);
        g[v][1].x.pb(-1e18);
        std::vector<int> chain;
        for(int i = head[v];i;i = e[i].nxt){
            if(e[i].to == fa[v] || e[i].to == son[v]) continue;
            get1(e[i].to);chain.pb(e[i].to);
        }
        NODE res = work2(chain,0,(int)chain.size()-1);
        upmax(g[v][1],res.f[1]);
        upmax(g[v][0],res.f[0]);
    }
    
    signed main(){
        int l,r;
        scanf("%*d%lld%lld%lld",&n,&l,&r);
        FOR(i,2,n){
            int u,v,w;scanf("%lld%lld%lld",&u,&v,&w);
            add(u,v,w);
        }
        dfs1(1);dfs2(1,1);
        get1(1);
    //    DEBUG(g[1][0][2]);
    //    DEBUG(g[1][1][2]);
        Poly ans;
        upmax(ans,g[1][0]);upmax(ans,g[1][1]);
        FOR(i,l,r){
            if(i > ans.deg() || ans[i] < -9e17) printf("- ");
            else printf("%lld ",ans[i]);
        }
        puts("");
        return 0;
    }
    
  • 相关阅读:
    VS中常用设置记录
    MSBUILD结合批处理编译
    Linq to XML 基本类
    在Winform和WPF中注册全局快捷键
    Unity 配置文件 基本设置
    C# 通用Clone
    三次样条插值特点与实现 (引用了一点别人代码,但做了改动!)
    修正短时自相关函数
    矩阵的基本运算
    去红眼不完善 MATLAB 代码
  • 原文地址:https://www.cnblogs.com/rainair/p/14471571.html
Copyright © 2011-2022 走看看