1 条题解

  • 0
    @ 2025-5-5 12:31:04

    题目分析

    我们需要从给定的 nn 个区间 [ai,bi][a_i, b_i] 中,每个区间至少选择 cic_i 个数,构造一个新的集合 ZZ。求在满足所有约束条件下,ZZ 至少包含多少个数。

    解题思路

    1. 变量定义

      • SiS_i 表示从 11ii 中被选出的数的个数。
      • 目标是求 S50001S_{50001}(即整个范围内至少选多少个数)。
    2. 约束条件

      • 非递减约束SiSi1S_i \geq S_{i-1},即从 11ii 选的数不会比 11i1i-1 选的数少。 [ S_i \geq S_{i-1} ]
      • 相邻差约束SiSi11S_i - S_{i-1} \leq 1,即相邻位置最多选 11 个数。 [ S_{i-1} \geq S_i - 1 ]
      • 区间约束:对于每个区间 [ai,bi][a_i, b_i],至少选 cic_i 个数。 [ S_{b_i} \geq S_{a_i - 1} + c_i ]
    3. 图的构建

      • 将不等式转化为图的边:
        • SiSi1S_i \geq S_{i-1}:从 i1i-1ii 连一条权值为 00 的边。
        • Si1Si1S_{i-1} \geq S_i - 1:从 iii1i-1 连一条权值为 1-1 的边。
        • SbiSai1+ciS_{b_i} \geq S_{a_i - 1} + c_i:从 ai1a_i - 1bib_i 连一条权值为 cic_i 的边。
      • 由于 aia_ibib_i 可能从 00 开始,我们统一将其 +1+1,避免与源点 00 冲突。
    4. 最长路求解

      • 由于约束条件是 SiSj+wS_i \geq S_j + w,我们需要求最长路。
      • 从源点 00 出发,计算到 5000150001 的最长路,S50001S_{50001} 即为答案。

    关键点

    • 源点的可达性
      • 由于约束 SiSi1S_i \geq S_{i-1} 保证了从 00 出发可以遍历所有点,因此源点 00 能到达所有边。
    • 边界处理
      • 将输入区间 [ai,bi][a_i, b_i]aia_ibib_i+1+1,避免 00 下标问题。

    复杂度分析

    • 时间复杂度
      • 最长路计算(如 SPFA)的最坏情况为 O(nm)O(nm),其中 nn 是点数,mm 是边数。
    • 空间复杂度
      • 存储图的边和距离数组,空间复杂度为 O(n+m)O(n + m)
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    const int N = 50010, M = 150010;
    
    int n;
    int h[N],w[M],e[M],ne[M],idx;
    int dist[N];
    int q[N];
    bool st[N];
    
    void add(int a,int b,int c){
    	e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
    }
    
    void spfa(){
    	memset(dist,-0x3f,sizeof dist);
    	int hh = 0, tt = 1;
    	dist[0] = 0;
    	q[0] = 0;
    	st[0] = true;
    	while(hh != tt){
    		int t = q[hh++];
    		if(hh == N) hh = 0;
    		st[t] = false;
    		for(int i = h[t]; ~i; i = ne[i]){
    			int j = e[i];
    			if(dist[j] < dist[t] + w[i]){
    				dist[j] = dist[t] + w[i];
    				if(!st[j]){
    					q[tt++] = j;
    					if(tt == N) tt = 0;
    					st[j] = true;
    				}
    			}
    		}
    	}
    }
    
    int main(int argc, char** argv) {
    	scanf("%d",&n);
    	memset(h,-1,sizeof h);
    	for(int i = 1; i <= 50001; i++){
    		add(i-1,i,0);
    		add(i,i-1,-1);
    	}
    	for(int i = 0; i < n; i++){
    		int a,b,c;
    		scanf("%d%d%d",&a,&b,&c);
    		a++; b++;
    		add(a-1,b,c);
    	}
    	spfa();
    	printf("%d",dist[50001]);
    	return 0;
    }
    • 1

    信息

    ID
    202
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者