• 历年NOIP水题泛做


    快noip了就乱做一下历年的noip题目咯..


    noip2014 飞扬的小鸟

    其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时..

    就是$f_{i,j}$表示在第$i$个位置高度为$j$的时候最小点击次数

    递推的话对于上升的情况只做一次,后面几次在后面再做..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 10010;
    const int Maxm = 1010;
    const int inf = 1e9;
    int f[2][Maxm];
    int n, m, K;
    int l[Maxn], u[Maxn]; bool p[Maxn];
    int X[Maxn], Y[Maxn];
    int _min ( int x, int y ){ return x < y ? x : y; }
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &n, &m, &K );
        l[0] = 0; u[0] = m+1;
        for ( i = 1; i <= n; i ++ ){ scanf ( "%d%d", &X[i], &Y[i] ); l[i] = 0; u[i] = m+1; }
        for ( i = 1; i <= K; i ++ ){
            int x;
            scanf ( "%d", &x );
            p[x] = true;
            scanf ( "%d%d", &l[x], &u[x] );
        }
        int st = 0;
        for ( i = 0; i <= m; i ++ ) f[st][i] = 0;
        int num = 0;
        for ( i = 1; i <= n; i ++ ){
            st = st^1;
            for ( j = 0; j <= m; j ++ ) f[st][j] = inf;
            bool bk = false;
            for ( j = l[i-1]+1; j < u[i-1]; j ++ ){
                if ( f[st^1][j] == inf ) continue;
                bk = true;
                f[st][_min(j+X[i],m)] = _min ( f[st][_min(j+X[i],m)], f[st^1][j]+1 );
            }
            for ( j = 0; j <= m; j ++ ){
                if ( f[st][j] != inf ) f[st][_min(j+X[i],m)] = _min ( f[st][_min(j+X[i],m)], f[st][j]+1 );
            }
            for ( j = l[i-1]+1; j < u[i-1]; j ++ ){
                if ( f[st^1][j] == inf ) continue;
                if ( j-Y[i] > l[i] && j-Y[i] < u[i] ) f[st][j-Y[i]] = _min ( f[st][j-Y[i]], f[st^1][j] );
            }
            if ( bk == false ){ printf ( "0
    %d
    ", num-1 ); return 0; }
            if ( p[i] == true ) num ++;
        }
        int ans = inf;
        for ( i = 1; i <= m; i ++ ) ans = _min ( ans, f[st][i] );
        printf ( "1
    %d
    ", ans );
        return 0;
    }

      


    noip2013 货车运输

    就是裸的最大瓶颈树..

    通俗点说就是最大生成树再用st表维护一下路径最小值..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 10010;
    const int Maxm = 50010;
    struct node {
        int y, next, d;
    }a[Maxn*2]; int first[Maxn], len;
    void ins ( int x, int y, int d ){
        len ++;
        a[len].y = y; a[len].d = d;
        a[len].next = first[x]; first[x] = len;
    }
    struct lnode {
        int x, y, d;
    }list[Maxm];
    bool cmp ( lnode x, lnode y ){ return x.d > y.d; }
    int n, m, q;
    int fa[Maxn]; bool fw[Maxn];
    int ff ( int x ){
        if ( fa[x] == x ) return x;
        return fa[x] = ff (fa[x]);
    }
    int minn[Maxn][15], fat[Maxn][15], dep[Maxn];
    int _min ( int x, int y ){ return x < y ? x : y; }
    void dfs ( int x, int f ){
        fw[x] = true;
        for ( int i = 1; i <= 14; i ++ ){
            fat[x][i] = fat[fat[x][i-1]][i-1];
            minn[x][i] = _min ( minn[x][i-1], minn[fat[x][i-1]][i-1] );
        }
        for ( int k = first[x]; k; k = a[k].next ){
            int y = a[k].y;
            if ( y == f ) continue;
            fat[y][0] = x;
            minn[y][0] = a[k].d;
            dep[y] = dep[x]+1;
            dfs ( y, x );
        }
    }
    int lca ( int x, int y ){
        int ret = 0x7fffffff;
        if ( dep[x] < dep[y] ) swap ( x, y );
        for ( int i = 14; i >= 0; i -- ){
            if ( dep[fat[x][i]] >= dep[y] ){
                ret = _min ( ret, minn[x][i] );
                x = fat[x][i];
            }
        }
        if ( x == y ) return ret;
        for ( int i = 14; i >= 0; i -- ){
            if ( fat[x][i] != fat[y][i] ){
                ret = _min ( ret, minn[x][i] );
                ret = _min ( ret, minn[y][i] );
                x = fat[x][i]; y = fat[y][i];
            }
        }
        return _min ( ret, _min ( minn[x][0], minn[y][0] ) );
    }
    int main (){
        int i, j, k;
        scanf ( "%d%d", &n, &m );
        for ( i = 1; i <= m; i ++ ){
            scanf ( "%d%d%d", &list[i].x, &list[i].y, &list[i].d );
        }
        sort ( list+1, list+m+1, cmp );
        for ( i = 1; i <= n; i ++ ) fa[i] = i;
        for ( i = 1; i <= m; i ++ ){
            int fx = ff (list[i].x), fy = ff (list[i].y);
            if ( fx != fy ){
                fa[fy] = fx;
                ins ( list[i].x, list[i].y, list[i].d );
                ins ( list[i].y, list[i].x, list[i].d );
            }
        }
        for ( i = 1; i <= n; i ++ ){
            if ( fw[i] == false ){ dep[i] = 1; dfs ( i, 0 ); }
        }
        scanf ( "%d", &q );
        for ( i = 1; i <= q; i ++ ){
            int x, y;
            scanf ( "%d%d", &x, &y );
            int fx = ff (x), fy = ff (y);
            if ( fx != fy ) printf ( "-1
    " );
            else printf ( "%d
    ", lca ( x, y ) );
        }
        return 0;
    }
    

      


    noip2015 跳石头

    二分答案,然后找第一个距离超过这个答案的使用,扫一遍即可

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 50010;
    int a[Maxn], n, m, L;
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &L, &n, &m );
        for ( i = 1; i <= n; i ++ ) scanf ( "%d", &a[i] );
        a[++n] = L;
        int l = 1, r = L, ret;
        while ( l <= r ){
            int mid = ( l + r ) >> 1;
            int last = 0, sum = 0;
            for ( i = 1; i <= n; i ++ ){
                if ( a[i]-last >= mid ) last = a[i];
                else sum ++;
            }
            if ( sum <= m ){ ret = mid; l = mid+1; }
            else r = mid-1;
        }
        printf ( "%d
    ", ret );
        return 0;
    }
    

      


    noip2015 子串

    哇我去年居然会做这道题 然而我现在好像不会了..

    $f_{i,j,k}$表示现在在第$i$块,小串匹配到$j$,大串匹配到$k$的方案数

    然后就可以这样搞:$$f_{i,j,k}=sumlimits_{p=0}^{k-1}f_{i-1,j-1,p}+f_{i,j-1,k-1} imes (s2[j-1]==s1[k-1])$$

    那么对于前面的只要维护一个前缀和就可以了..

    再给一道题吧,也是前缀和相关:CodeForces 587B 记得当年就是从这题吸取了经验的(感谢胖涛..)

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 1010;
    const int Maxm = 210;
    const int Mod = 1000000007;
    char a[Maxn], b[Maxm];
    int n, m, K;
    int f[2][Maxm][Maxn];
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &n, &m, &K );
        scanf ( "%s", a+1 );
        scanf ( "%s", b+1 );
        int st = 0;
        for ( i = 0; i <= n; i ++ ) f[0][0][i] = 1;
        for ( k = 1; k <= K; k ++ ){
            st = st^1;
            memset ( f[st], 0, sizeof (f[st]) );
            for ( i = 1; i <= m; i ++ ){
                for ( j = 1; j <= n; j ++ ){
                    if ( b[i] == a[j] ){
                        f[st][i][j] = ( f[st][i][j] + f[st^1][i-1][j-1] ) % Mod;
                        if ( b[i-1] == a[j-1] ) f[st][i][j] = ( f[st][i][j] + f[st][i-1][j-1] ) % Mod;
                    }
                }
            }
            for ( i = 1; i <= m; i ++ ){
                for ( j = 1; j <= n; j ++ ) f[st][i][j] = ( f[st][i][j] + f[st][i][j-1] ) % Mod;
            }
        }
        printf ( "%d
    ", f[st][m][n] );
        return 0;
    }
    

      


    noip2015 运输计划

    先预处理每条路径长度,找出最长的那条记为$ss$

    二分答案,超过该答案的路径在树上差分标记一下,那么如果某个点子树所有标记和等于超过的路径数,证明该点与其父亲的边可能要割

    然后在这些边中找到最大值,看$ss$减去这个值是否在二分的答案以内就行了

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 300010;
    struct node {
        int y, next, d;
    }a[Maxn*2]; int first[Maxn], len;
    void ins ( int x, int y, int d ){
        len ++;
        a[len].y = y; a[len].d = d;
        a[len].next = first[x]; first[x] = len;
    }
    int n, m;
    int fa[Maxn][23], sum[Maxn][23], dep[Maxn];
    void dfs ( int x, int f ){
        for ( int i = 1; i <= 22; i ++ ){
            fa[x][i] = fa[fa[x][i-1]][i-1];
            sum[x][i] = sum[x][i-1] + sum[fa[x][i-1]][i-1];
        }
        for ( int k = first[x]; k; k = a[k].next ){
            int y = a[k].y;
            if ( y == f ) continue;
            fa[y][0] = x;
            sum[y][0] = a[k].d;
            dep[y] = dep[x]+1;
            dfs ( y, x );
        }
    }
    struct qnode {
        int x, y, lca, dist;
    }q[Maxn];
    void get_lca ( qnode &p ){
        int x = p.x, y = p.y;
        p.dist = 0;
        if ( dep[x] < dep[y] ) swap ( x, y );
        for ( int i = 22; i >= 0; i -- ){
            if ( dep[fa[x][i]] >= dep[y] ){
                p.dist += sum[x][i];
                x = fa[x][i];
            }
        }
        if ( x == y ){ p.lca = x; return; }
        for ( int i = 22; i >= 0; i -- ){
            if ( fa[x][i] != fa[y][i] ){
                p.dist += sum[x][i];
                p.dist += sum[y][i];
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        p.dist += sum[x][0]+sum[y][0];
        p.lca = fa[x][0];
    }
    int bj[Maxn];
    int _max ( int x, int y ){ return x > y ? x : y; }
    int DFS ( int x, int f, int mid ){
        int ret = -1;
        for ( int k = first[x]; k; k = a[k].next ){
            int y = a[k].y;
            if ( y == f ) continue;
            ret = _max ( DFS ( y, x, mid ), ret );
            if ( bj[y] == mid ) ret = _max ( ret, a[k].d );
            bj[x] += bj[y];
        }
        return ret;
    }
    int main (){
        int i, j, k;
        scanf ( "%d%d", &n, &m );
        for ( i = 1; i < n; i ++ ){
            int x, y, d;
            scanf ( "%d%d%d", &x, &y, &d );
            ins ( x, y, d ); ins ( y, x, d );
        }
        dfs ( 1, 0 );
        int ss = 0;
        for ( i = 1; i <= m; i ++ ){
            scanf ( "%d%d", &q[i].x, &q[i].y );
            get_lca (q[i]);
            ss = _max ( ss, q[i].dist );
        }
        int l = 1, r = ss, ret;
        while ( l <= r ){
            int mid = ( l + r ) >> 1;
            int ssum = 0;
            for ( i = 1; i <= n; i ++ ) bj[i] = 0;
            for ( i = 1; i <= m; i ++ ){
                if ( q[i].dist > mid ){
                    bj[q[i].x] ++; bj[q[i].y] ++;
                    bj[q[i].lca] -= 2;
                    ssum ++;
                }
            }
            if ( ss-DFS ( 1, 0, ssum ) <= mid ){ ret = mid; r = mid-1; }
            else l = mid+1;
        }
        printf ( "%d
    ", ret );
        return 0;
    }
    

      


    noip2013 华容道

    记录f[i][j][k][l]为被标记的点在(i,j),空白点在k方向,使其移动到l方向的最小步数

    这个东西是可以在$O(n^4)$预处理出来的

    那么对于每一个询问,先算出空白点移动到标记点4个方向上的步数,然后就是最短路的事情了

    推荐使用dijkstra算法,能够保证在$O(qn^2logn^2)$内算出..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int dx[4] = { 0, 1, -1, 0 };
    const int dy[4] = { 1, 0, 0, -1 };
    const int inf = 0x7fffffff;
    int f[35][35][4][4], num[35][35][4], tot;
    int dis[4010];
    bool v[35][35];
    int n, m, q;
    int dist[35][35]; bool bo[35][35];
    struct zb {
        int x, y;
    }e, s, t;
    void bfs1 ( int xx, int yy, int k ){
        queue <zb> q;
        for ( int i = 0; i <= n+1; i ++ ) for ( int j = 0; j <= m+1; j ++ ) dist[i][j] = inf, bo[i][j] = false;
        zb x;
        x.x = xx+dx[k]; x.y = yy+dy[k];
        q.push (x);
        dist[x.x][x.y] = 0; bo[x.x][x.y] = true;
        while ( !q.empty () ){
            x = q.front (); q.pop ();
            for ( int i = 0; i < 4; i ++ ){
                zb y;
                y.x = x.x+dx[i]; y.y = x.y+dy[i];
                if ( v[y.x][y.y] == false || bo[y.x][y.y] == true ) continue;
                dist[y.x][y.y] = dist[x.x][x.y]+1;
                bo[y.x][y.y] = true;
                q.push (y);
            }
        }
        for ( int i = 0; i < 4; i ++ ){
            f[xx][yy][k][i] = dist[xx+dx[i]][yy+dy[i]];
        }
    }
    void bfs2 (){
        queue <zb> q;
        for ( int i = 0; i <= n+1; i ++ ) for ( int j = 0; j <= m+1; j ++ ) dist[i][j] = inf, bo[i][j] = false;
        q.push (e);
        dist[e.x][e.y] = 0; bo[e.x][e.y] = true;
        while ( !q.empty () ){
            zb x = q.front (); q.pop ();
            for ( int i = 0; i < 4; i ++ ){
                zb y;
                y.x = x.x+dx[i]; y.y = x.y+dy[i];
                if ( v[y.x][y.y] == false || bo[y.x][y.y] == true ) continue;
                dist[y.x][y.y] = dist[x.x][x.y]+1;
                bo[y.x][y.y] = true;
                q.push (y);
            }
        }
    }
    struct node {
        int y, next, d;
    }a[160010]; int first[4010], len;
    void ins ( int x, int y, int d ){
        len ++;
        a[len].y = y; a[len].d = d;
        a[len].next = first[x]; first[x] = len;
    }
    struct knode {
        int x, dis;
    };
    bool operator < ( knode x, knode y ){ return x.dis > y.dis; }
    priority_queue <knode> Q;
    void dij (){
        while ( !Q.empty () ){
            knode x = Q.top (); Q.pop ();
            if ( dis[x.x] < x.dis ) continue;
            for ( int k = first[x.x]; k; k = a[k].next ){
                int y = a[k].y;
                if ( dis[y] > dis[x.x]+a[k].d ){
                    dis[y] = dis[x.x]+a[k].d;
                    knode p;
                    p.x = y; p.dis = dis[y];
                    Q.push (p);
                }
            }
        }
    }
    int _min ( int x, int y ){ return x < y ? x : y; }
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &n, &m, &q );
        for ( i = 1; i <= n; i ++ ){
            for ( j = 1; j <= m; j ++ ){
                int x;
                scanf ( "%d", &x );
                if ( x == 1 ) v[i][j] = true;
            }
        }
        tot = 0;
        for ( i = 1; i <= n; i ++ ){
            for ( j = 1; j <= m; j ++ ){
                if ( v[i][j] == false ) continue;
                for ( k = 0; k < 4; k ++ ){
                    if ( v[i+dx[k]][j+dy[k]] == true ){
                        v[i][j] = false;
                        bfs1 ( i, j, k );
                        v[i][j] = true;
                        num[i][j][k] = ++tot;
                    }
                    else for ( int l = 0; l < 4; l ++ ) f[i][j][k][l] = inf;
                }
            }
        }
        while ( q -- ){
            scanf ( "%d%d%d%d%d%d", &e.x, &e.y, &s.x, &s.y, &t.x, &t.y );
            if ( s.x == t.x && s.y == t.y ){ printf ( "0
    " ); continue; }
            v[s.x][s.y] = false;
            bfs2 ();
            v[s.x][s.y] = true;
            for ( j = 1; j <= tot; j ++ ) first[j] = 0, dis[j] = inf;
            len = 0;
            for ( j = 0; j < 4; j ++ ){
                if ( dist[s.x+dx[j]][s.y+dy[j]] != inf ){
                    knode p;
                    p.x = num[s.x][s.y][j]; p.dis = dist[s.x+dx[j]][s.y+dy[j]];
                    Q.push (p);
                    dis[num[s.x][s.y][j]] = dist[s.x+dx[j]][s.y+dy[j]];
                }
            }
            for ( i = 1; i <= n; i ++ ){
                for ( j = 1; j <= m; j ++ ){
                    for ( k = 0; k < 4; k ++ ){
                        if ( v[i+dx[k]][j+dy[k]] == true ){
                            for ( int l = 0; l < 4; l ++ ){
                                if ( f[i][j][k][l] != inf ) ins ( num[i][j][k], num[i][j][l], f[i][j][k][l] );
                            }
                            ins ( num[i][j][k], num[i+dx[k]][j+dy[k]][3-k], 1 );
                        }
                    }
                }
            }
            dij ();
            int ans = inf;
            for ( i = 0; i < 4; i ++ ){
                if ( num[t.x][t.y][i] != 0 ) ans = _min ( ans, dis[num[t.x][t.y][i]] );
            }
            if ( ans != inf ) printf ( "%d
    ", ans );
            else printf ( "-1
    " );
        }
        return 0;
    }
    

      


    noip2011 选择客栈

    一开始看错题了.. 做法其实没啥区别就是强行解释一下

    由于题目给出的$p$是不会变的,然后就可以瞎搞处理了,时间复杂度是$O(k*小于等于p的节点数)$

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxc = 55;
    int c[Maxc], ans[Maxc];
    int n, K, p;
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &n, &K, &p );
        int anss = 0;
        for ( i = 1; i <= n; i ++ ){
            int fl, x;
            scanf ( "%d%d", &fl, &x );
            c[fl] ++;
            if ( x <= p ){
                for ( j = 0; j < K; j ++ ) ans[j] = c[j];
            }
            anss += ans[fl];
            if ( x <= p ) anss --;
        }
        printf ( "%d
    ", anss );
        return 0;
    }
    

      


    noip2012 开车旅行

    由于两人决策唯一性,那么可以预处理出从某点开始走$2^i$步到达的点..

    讲道理的话其实也就只需要处理$f_{i,0}$和$f_{i,1}$,后面的都可以倍增求

    第一问就枚举点倍增搞

    其他问就直接跑..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <set>
    #define LL long long
    using namespace std;
    const int Maxn = 100010;
    const int inf = 0x7fffffff;
    struct no {
        int x, h;
    };
    bool operator < ( no x, no y ){ return x.h < y.h; }
    set <no> S;
    set <no> :: iterator it;
    int h[Maxn], n, m;
    int fa[Maxn][22], fb[Maxn][22], f[Maxn][22];
    no gob[Maxn];
    void pre (){
        int i, j, k;
        no p;
        p.x = n; p.h = h[n];
        S.insert (p);
        for ( i = n-1; i >= 1; i -- ){
            p.x = i; p.h = h[i];
            it = S.lower_bound (p);
            no fir, sec;
            fir.h = inf; sec.h = inf;
            if ( it != S.end () ){
                fir.x = (*it).x; fir.h = (*it).h-h[i];
                it ++;
                if ( it != S.end () ) sec.x = (*it).x, sec.h = (*it).h-h[i];
                it --;
            }
            if ( it != S.begin () ){
                it --;
                if ( h[i]-(*it).h <= fir.h ){
                    sec = fir;
                    fir.x = (*it).x; fir.h = h[i]-(*it).h;
                }
                else if ( h[i]-(*it).h <= sec.h ){
                    sec.x = (*it).x; sec.h = h[i]-(*it).h;
                }
                if ( it != S.begin () ){
                    it --;
                    if ( h[i]-(*it).h <= sec.h ){
                        sec.x = (*it).x; sec.h = h[i]-(*it).h;
                    }
                }
            }
            if ( sec.h != inf ){
                f[i][0] = sec.x; f[i][1] = gob[sec.x].x;
                fa[i][0] = fa[i][1] = sec.h;
                fb[i][0] = 0; fb[i][1] = gob[sec.x].h;
                for ( j = 2; j <= 21 && i+(1<<(j-1)) <= n; j ++ ){
                    f[i][j] = f[f[i][j-1]][j-1];
                    fa[i][j] = fa[i][j-1] + fa[f[i][j-1]][j-1];
                    fb[i][j] = fb[i][j-1] + fb[f[i][j-1]][j-1];
                }
            }
            if ( fir.h != inf ) gob[i] = fir;
            S.insert (p);
        }
    }
    struct node {
        int na, nb;
    };
    void gogogo ( int st, int xx, node &jl ){
        jl.na = jl.nb = 0;
        int i;
        for ( i = 21; i >= 0; i -- ){
            if ( fa[st][i]+fb[st][i] <= xx && f[st][i] != 0 ){
                jl.na += fa[st][i];
                jl.nb += fb[st][i];
                xx -= fa[st][i]+fb[st][i];
                st = f[st][i];
            }
        }
    }
    int main (){
        int i, j, k;
        scanf ( "%d", &n );
        for ( i = 1; i <= n; i ++ ) scanf ( "%d", &h[i] );
        pre ();
        int x0, s0;
        scanf ( "%d", &x0 );
        s0 = n; node ans, po;
        ans.na = ans.nb = 0;
        for ( i = n-1; i >= 1; i -- ){
            gogogo ( i, x0, po );
            if ( (LL)po.na*ans.nb < (LL)ans.na*po.nb || ( (LL)po.na*ans.nb == (LL)ans.na*po.nb && h[i] > h[s0] ) || s0 == n || ( ans.nb == 0 && po.nb != 0 ) ){
                s0 = i;
                ans = po;
            }
        }
        printf ( "%d
    ", s0 );
        scanf ( "%d", &m );
        for ( i = 1; i <= m; i ++ ){
            int ss, xx;
            scanf ( "%d%d", &ss, &xx );
            gogogo ( ss, xx, po );
            printf ( "%d %d
    ", po.na, po.nb );
        }
        return 0;
    }
    

      


    noip2011 观光公交

    记录$time_i$是到达$i$点的最小时刻,$last_i$是最迟一个到达$i$点的人的时刻

    那么$time_i=max(time_{i-1},last_{i-1})+d_i$

    可以处理出修改每一个$d_i$所影响的人数

    每次贪心找一个最大的减去就好了

    时间复杂度是$O(nk)$的..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 100010;
    int time[Maxn], d[Maxn], last[Maxn];
    int n, m, K;
    struct lnode {
        int st, ed, t;
    }list[Maxn];
    int sum[Maxn], f[Maxn];
    int _max ( int x, int y ){ return x > y ? x : y; }
    int main (){
        int i, j, k;
        scanf ( "%d%d%d", &n, &m, &K );
        for ( i = 2; i <= n; i ++ ) scanf ( "%d", &d[i] );
        for ( i = 1; i <= m; i ++ ){
            scanf ( "%d%d%d", &list[i].t, &list[i].st, &list[i].ed );
            last[list[i].st] = _max ( last[list[i].st], list[i].t );
            sum[list[i].ed] ++;
        }
        time[1] = 0;
        for ( i = 2; i <= n; i ++ ){
            time[i] = _max ( time[i-1], last[i-1] ) + d[i];
            sum[i] += sum[i-1];
        }
        int ans = 0;
        for ( i = 1; i <= m; i ++ ){
            ans += time[list[i].ed] - list[i].t;
        }
        while ( K -- ){
            f[n] = n;
            for ( i = n-1; i >= 2; i -- ){
                if ( time[i] > last[i] ) f[i] = f[i+1];
                else f[i] = i;
            }
            int Max = 0, p;
            for ( i = 2; i <= n; i ++ ){
                if ( sum[f[i]]-sum[i-1] > Max && d[i] > 0 ){
                    Max = sum[f[i]]-sum[i-1];
                    p = i;
                }
            }
            ans -= Max; d[p] --;
            for ( i = 2; i <= n; i ++ ){
                time[i] = _max ( time[i-1], last[i-1] ) + d[i];
            }
        }
        printf ( "%d
    ", ans );
        return 0;
    }
    

      


  • 相关阅读:
    Azure WAF防火墙工作原理分析和配置向导
    多云时代,海外微软Azure云与国内阿里云专线打通性能测试
    【Hololens】微软Hololens虚拟现实视频集
    【Azure】Azure学习方法和学习资料
    LINUX ON AZURE 安全建议(全)
    编程行业之网络贩卖生存
    Bootstrap
    我谷首开博客
    Noip2018普及组初赛试题解题报告
    奇yin技巧
  • 原文地址:https://www.cnblogs.com/darklove/p/6063721.html
Copyright © 2020-2023  润新知