• P1295 [TJOI2011]书架


    题目链接

    点我跳转

    题目大意

    给出一个长度为 (n) 的序列 (a) ,请将 (h) 分成若干段,满足每段数字之和都不超过 (m) ,最小化每段的最大值之和。

    解题思路

    先考虑 (30) 分做法

    定义 (dp[i]) 表示将前 (i) 个数分成若干段的最小代价

    那么易推出 (dp[i] = max(dp[i] , dp[j - 1] + max(a[j] sim a[i]))) ,最后答案为 (dp[n])

    考虑 $ 100$ 分做法

    定义 (l[i]) 为左边第一个大于 (a[i]) 的数的位置 , (l[i])可以用单调栈求出

    定义 (get(i)) 为满足 (a[get(i)] + ... + a[i] <= m) 的临界位置 , (get(i))可以用二分来求

    那么 (dp_i = min(min(dp_{get(i)} sim dp_{l_i}) , min(dp_{l_i + 1} sim dp_i) + a_i))

    可以用线段树维护三个信息 (ans , pre , lazy)

    其中 (ans) 表示 (dp[j] , pre) 表示 (dp[j - 1] ,lazy) 表示 (max(a[j] sim a[i])),那么 (ans = pre + lazy)

    现从 (a1) 开始遍历,每加入一个 (ai) 会有以下三步

    1、(l(i)+1sim i) 区间的 (lazy) 变为 (a_i)(get_i sim l_i) 区间的 (lazy) 不变)

    2、第 (i) 个位置的 (ans = dp_{i - 1})

    3、(dp_i = min(ans_{get_i} sim ans_i))

    所以我们只要用线段树进行区间修改,单点修改,区间查询即可

    AC_Code

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int INF (0x3f3f3f3f3fll);
    const int N = 3e5 + 10;
    struct Tree{
    	int l , r ;
    	int mi , ans , lazy;
    }tree[N << 2];
    void push_up(int rt)
    {
    	tree[rt].mi = min(tree[rt << 1].mi , tree[rt << 1 | 1].mi);
    	tree[rt].ans = min(tree[rt << 1].ans , tree[rt << 1 | 1].ans);
    }
    void push_down(int rt)
    {
    	if(tree[rt].lazy == INF) return ;
    	int x = tree[rt].lazy;
    	tree[rt].lazy = INF;
    	tree[rt << 1].ans = tree[rt << 1].mi + x;
    	tree[rt << 1 | 1].ans = tree[rt << 1 | 1].mi + x;
    	tree[rt << 1 | 1].lazy = x , tree[rt << 1].lazy = x;
    }
    void build(int l , int r , int rt , int *a)
    {
    	tree[rt].l = l , tree[rt].r = r;
    	if(l == r)
    	{
    		tree[rt].mi = tree[rt].ans = a[l]; 
    		tree[rt].lazy = INF;
    		return ;
    	}
    	int mid = l + r >> 1;
    	build(l , mid , rt << 1 , a);
    	build(mid + 1 , r , rt << 1 | 1 , a);
    	push_up(rt);
    }
    void update(int pos , int val, int rt)
    {
    	int l = tree[rt].l , r = tree[rt].r;
    	if(l == r) 
    	{
    		tree[rt].mi = val;
    		return ;
    	}
    	if(tree[rt].lazy != INF) push_down(rt);
    	int mid = l + r >> 1;
    	if(pos <= mid) update(pos , val , rt << 1);
    	else update(pos , val , rt << 1 | 1);
    	push_up(rt); 
    }
    void update_range(int L , int R , int rt , int val)
    {
    	if(tree[rt].r<L||tree[rt].l>R) return;
    	int l = tree[rt].l , r = tree[rt].r;
    	if(L <= l && r <= R)
    	{
    		tree[rt].lazy = val;
    		tree[rt].ans = tree[rt].mi + val;
    		return; 
    	}
    	if(tree[rt].lazy != INF) push_down(rt);
    	int mid = l + r >> 1;
    	if(L <= mid) update_range(L , R , rt << 1 , val);
    	if(R > mid) update_range(L , R , rt << 1 | 1 , val); 
    	push_up(rt);
    }
    int query_min(int L , int R , int rt)
    {
    	int l = tree[rt].l , r = tree[rt].r;
    	if(L <= l && r <= R)
    	{
    		return tree[rt].ans;
    	}
    	if(tree[rt].lazy != INF) push_down(rt);
    	int mid = l + r >> 1;
    	int ans = INF;
    	if(L <= mid) ans = min(ans , query_min(L , R , rt << 1));
    	if(R > mid) ans = min(ans , query_min(L , R , rt << 1 | 1));
    	return ans;
    }
    int a[N] , l[N] , dp[N] , sum[N] , n , m;
    stack<int>sta;
    int get(int i)
    {
    	int l = 0 , r = i , res = 0;
    	while(l <= r)
    	{
    		int mid = l + r >> 1;
    		if(sum[i] - sum[mid - 1] > m) l = mid + 1;
    		else r = mid - 1 , res = mid; 
    	}
    	return max(1LL , res);
    }
    signed main()
    {
    	for(int i = 0 ; i <= N - 10 ; i ++) dp[i] = INF;
    	cin >> n >> m;
    	a[1] = 0 , dp[1] = 0;
    	build(1 , n + 10 , 1 , dp) , update(1 , 0 , 1);
    	for(int i = 2 ; i <= n + 1 ; i ++) cin >> a[i] , sum[i] = sum[i - 1] + a[i];
    	for(int i = 1 ; i <= n + 1 ; i ++)
    	{
    		while(sta.size() && a[sta.top()] < a[i]) sta.pop();
    		if(sta.size()) l[i] = sta.top();
    		else l[i] = 0;
    		sta.push(i);
    	}
    	for(int i = 2 ; i <= n + 1 ; i ++)
    	{	
    		update(i , dp[i - 1] , 1); 
    		int x = get(i) , y = l[i];
    		update_range(y + 1 , i , 1 , a[i]);
    		dp[i] = query_min(x , i , 1);	
    	}
    	cout << dp[n + 1] << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    myeclipse的debug模式启动不了,但run模式可以启动
    修改tomcat的端口号
    mybatis报错:Caused by: java.lang.IllegalArgumentException: Caches collection already contains value for com.crm.dao.PaperUserMapper
    mysql报错:java.sql.SQLException: Incorrect string value: 'xE4xB8x80xE6xACxA1...' for column 'excelName' at row 1
    修改tomcat命令黑窗口的名字
    myeclipse无法部署项目的解决
    我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?
    14个Java并发容器,你用过几个?
    6 种微服务 RPC 框架,你知道几个?
    Java中Set与Set<?>到底区别在哪?
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13861879.html
Copyright © 2020-2023  润新知