历年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\n%d\n", 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\n%d\n", 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\n" );
        else printf ( "%d\n", 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\n", ret );
    return 0;
}

  


noip2015 子串

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

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

然后就可以这样搞:$$f_{i,j,k}=\sum\limits_{p=0}^{k-1}f_{i-1,j-1,p}+f_{i,j-1,k-1}\times (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\n", 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\n", 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\n" ); 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\n", ans );
        else printf ( "-1\n" );
    }
    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\n", 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\n", 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\n", 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\n", ans );
    return 0;
}

  


 

posted @ 2016-11-14 22:17  Ra1nbow  阅读(214)  评论(0编辑  收藏  举报