题意:给你许多小区间[ai,bi],并且指定每一个小区间内至少包含ci个数。然后求一个长度最小区间 z, 使得与每一个小区间的相同元素都>=ci。
题解:
1.假设区间z=[s,t], sum[i]表示[s,t] ∩ [s,i] 的元素个数。那么[ai,bi] >= ci 则可以表示为sum[bi]-sum[ai-1]>=ci。
2.若i<=j,则 [s,t] ∩ [s,i] 的元素个数 <= [s,t] ∩ [s,j] 的元素个数,即:sum[i] <= sum[j]
3.若i<=j,则 sum[j] - sum[i] <= j-i
但是在本题中 0 <= ai <= bi 若用sum[ai-1]可能会产生下标位-1这样的情况,而这显然是不行,所以用sum[bi+1]-sum[ai]。(注意:要始终保持半开半闭区间这样的形式,避免边界处有重复计算)。
//AC #include <iostream> using namespace std; #define N 100009 #define INF 999999 bool mark[N]; int head[N], dis[N], que[N]; int m, size, lmin, rmax; struct Edge { int v, w, next; }; Edge edge[N*3]; void Spfa() { memset(mark,0,sizeof(mark)); for ( int i = lmin; i <= rmax; i++ ) dis[i] = INF; int u, v, front, rear; front = rear = 0; que[rear] = rmax+1; rear = ( rear + 1 ) % N; mark[rmax+1] = true; dis[rmax+1] = 0; while ( front != rear ) { u = que[front]; front = ( front + 1 ) % N; mark[u] = false; for ( int i = head[u]; i; i = edge[i].next ) { v = edge[i].v; if ( dis[v] > dis[u] + edge[i].w ) { dis[v] = dis[u] + edge[i].w; if ( ! mark[v] ) { que[rear] = v; rear = ( rear + 1 ) % N; mark[v] = true; } } } } } void add ( int u, int v, int w ) { size++; edge[size].v = v; edge[size].w = w; edge[size].next = head[u]; head[u] = size; } int main() { int a, b, c, i; scanf("%d",&m); size = 0; lmin = INF; rmax = -INF; memset(head,0,sizeof(head)); while ( m-- ) { scanf("%d%d%d",&a,&b,&c); add ( b+1, a, -c ); if ( a < lmin ) lmin = a; if ( b+1 > rmax ) rmax = b+1; } for ( i = lmin; i < rmax; i++ ) { add ( i+1, i, 0 ); add ( i, i+1, 1 ); } for ( i = lmin; i <= rmax; i++ ) add ( rmax+1, i, 0 ); Spfa(); printf("%d\n",dis[rmax]-dis[lmin]); return 0; }
//AC #include <iostream> using namespace std; #define N 100009 #define INF 999999 bool mark[N]; int head[N], dis[N], que[N]; int m, size, lmin, rmax, s; struct Edge { int v, w, next; }; Edge edge[N*3]; void Spfa() { memset(mark,0,sizeof(mark)); for ( int i = lmin; i <= rmax; i++ ) dis[i] = INF; s = rmax; // 换成lmin则错误 !!! int u, v, front, rear; front = rear = 0; que[rear] = s; rear = ( rear + 1 ) % N; mark[s] = true; dis[s] = 0; while ( front != rear ) { u = que[front]; front = ( front + 1 ) % N; mark[u] = false; for ( int i = head[u]; i; i = edge[i].next ) { v = edge[i].v; if ( dis[v] > dis[u] + edge[i].w ) { dis[v] = dis[u] + edge[i].w; if ( ! mark[v] ) { que[rear] = v; rear = ( rear + 1 ) % N; mark[v] = true; } } } } } void add ( int u, int v, int w ) { size++; edge[size].v = v; edge[size].w = w; edge[size].next = head[u]; head[u] = size; } int main() { int a, b, c, i; scanf("%d",&m); size = 0; lmin = INF; rmax = -INF; memset(head,0,sizeof(head)); while ( m-- ) { scanf("%d%d%d",&a,&b,&c); add ( b+1, a, -c ); if ( a < lmin ) lmin = a; if ( b+1 > rmax ) rmax = b+1; } for ( i = lmin; i < rmax; i++ ) { add ( i+1, i, 0 ); add ( i, i+1, 1 ); } // for ( i = lmin; i <= rmax; i++ ) // add ( rmax+1, i, 0 ); Spfa(); printf("%d\n",dis[rmax]-dis[lmin]); return 0; }