IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【XSY3535】购物(决策单调性优化DP,分治,结论) -> 正文阅读

[数据结构与算法]【XSY3535】购物(决策单调性优化DP,分治,结论)

题面

购物

题解

决策单调性全忘了……

先考虑暴力怎么做,我们可以设 f i , j f_{i,j} fi,j? 表示前 i i i 个商店买了 j j j 件物品的最小代价,然后有转移:
f i , j = min ? k = 0 j ( f i ? 1 , k + s a i , j ? k ) f_{i,j}=\min_{k=0}^j(f_{i-1,k}+sa_{i,j-k}) fi,j?=k=0minj?(fi?1,k?+sai,j?k?)
其中 s a i , j sa_{i,j} sai,j? 表示 a i , ? a_{i,*} ai,?? 的前缀和。

我们先来看一个决策单调性优化 DP 的模板题:给定两个长度为 n n n 的数组 f , g f,g f,g,其中 f , g f,g f,g 均单调不降,且 g g g 的差分数组 Δ g \Delta g Δg 单调不降,令 h k = min ? i + j = k ( f i + g j ) h_{k}=\min\limits_{i+j=k}(f_i+g_j) hk?=i+j=kmin?(fi?+gj?),求 h h h

结论是:随着 k = i + j k=i+j k=i+j 增大,最优决策点 i i i 单调不降。

证明:考虑对每个 i i i 绘出 f i f_i fi? h k h_{k} hk? 贡献的图像,设为 f i ( k ) f_i(k) fi?(k),那么对于任意两个 i 1 < i 2 i_1<i_2 i1?<i2? 和它们的函数图像:

在这里插入图片描述

这个图像包含的性质有: f i 1 ( k ) f_{i_1}(k) fi1??(k) f i 2 ( k ) f_{i_2}(k) fi2??(k) 形状相同、 f i 2 ( k ) f_{i_2}(k) fi2??(k) 起点在 f i 1 ( k ) f_{i_1}(k) fi1??(k) 右上方、 f i 1 ( k ) , f i 2 ( k ) f_{i_1}(k),f_{i_2}(k) fi1??(k),fi2??(k) 单调不降且导数不降。

那么必然存在一个阈值 X X X(两图像交点),使得在 X X X 之前都是 f i 1 ( k ) f_{i_1}(k) fi1??(k) 更优、在 X X X 之后都是 f i 2 ( k ) f_{i_2}(k) fi2??(k) 更优。

也就说明了,不存在 k 1 < k 2 k_1<k_2 k1?<k2? 满足在 k = k 1 k=k_1 k=k1? f i 2 ( k ) f_{i_2}(k) fi2??(k) 更优且在 k = k 2 k=k_2 k=k2? f i 1 ( k ) f_{i_1}(k) fi1??(k) 更优。即随着 k k k 增大,最优决策点 i i i 单调不降。

有了这个结论之后还不能直接做,因为虽然最优决策点 i i i 单调不降,但它不一定连续,即随着 k k k 增大, i i i 可能是跳跃前进的。

正确的方法是使用分治:我们暴力找到 k = m i d k=mid k=mid 时的最优决策点 i 0 i_0 i0?,然后我们就知道了当 k < m i d k<mid k<mid 时的最优决策点区间 [ 0 , i 0 ] [0,i_0] [0,i0?],和当 k > m i d k>mid k>mid 时的最优决策点区间 [ i 0 , n ] [i_0,n] [i0?,n],然后再分治下去做即可。一共 O ( log ? n ) O(\log n) O(logn) 层,每层暴力找最优决策点的时间总和为 O ( n ) O(n) O(n),时间复杂度 O ( n log ? n ) O(n\log n) O(nlogn)

再看回这一题:
f n , k = min ? i + j = k ( f n ? 1 , i + s a n , j ) f_{n,k}=\min_{i+j=k}(f_{n-1,i}+sa_{n,j}) fn,k?=i+j=kmin?(fn?1,i?+san,j?)
观察到式子中 f n ? 1 , ? f_{n-1,*} fn?1,?? s a n , ? sa_{n,*} san,?? 是单调不降的, s a n , ? sa_{n,*} san,?? 的差分数组 Δ s a n , ? \Delta sa_{n,*} Δsan,?? 第二位及之后都是单调不降的,但是却有可能 Δ s a n , 1 > Δ s a n , 2 \Delta sa_{n,1}>\Delta sa_{n,2} Δsan,1?>Δsan,2?

其实我们只需要对 j j j 是否大于等于 1 1 1 分类讨论处理一下就可以了:

  • f n , k = f n ? 1 , k + s a n , 0 f_{n,k}=f_{n-1,k}+sa_{n,0} fn,k?=fn?1,k?+san,0?
  • f n , k = min ? i + j = k , j ≥ 1 ( f n ? 1 , i + s a n , j ) f_{n,k}=\min\limits_{i+j=k,j\geq 1}(f_{n-1,i}+sa_{n,j}) fn,k?=i+j=k,j1min?(fn?1,i?+san,j?),在定义域 j ≥ 1 j\geq 1 j1 的情况下 s a n , j sa_{n,j} san,j? 的差分数组是单调不降的。

于是我们就可以做到 O ( n k log ? k ) O(nk\log k) O(nklogk) 了!

接着是第二个神仙的部分。

C 1 C_1 C1? 为商店全集,我们考虑将所有商店按 s a i , 1 sa_{i,1} sai,1? 排序,取出前 k k k 小,记为 S 1 S_1 S1?,显然 S 1 S_1 S1? 之外的商店都不可能取恰好 1 1 1 个物品,因为根据鸽巢原理此时 S 1 S_1 S1? 中肯定有一个商店为空(一个都没取),那么我们换成 S 1 S_1 S1? 中那个空的商店取 1 1 1 个肯定更优。

接着再考虑剩下的商店 C 2 = C 1 ? S 1 C_2=C_1-S_1 C2?=C1??S1?,我们已经知道了它们不可能取恰好 1 1 1 个。我们再将 C 2 C_2 C2? 中的商店按 s a i , 2 sa_{i,2} sai,2? 排序,取出前 ? k 2 ? \lfloor\frac{k}{2}\rfloor ?2k?? 小,记为 S 2 S_2 S2?,发现 C 2 C_2 C2? S 2 S_2 S2? 之外的商店也不可能取恰好 2 2 2 个物品,否则 S 2 S_2 S2? 中肯定有一个商店为空(注意 C 2 C_2 C2? 中商店要么取 0 0 0 个,要么取 2 2 2 个或以上,所以根据鸽巢原理 S 2 S_2 S2? 中肯定有一个商店为空),那么我们换成 S 2 S_2 S2? 中那个空的商店取 2 2 2 个肯定更优。

接着再考虑剩下的商店 C 3 = C 2 ? S 2 C_3=C_2-S_2 C3?=C2??S2?,我们已经知道了它们不可能取恰好 1 1 1 2 2 2 个,……。我们一直像这样排除下去,最后会得到若干个商店取的物品数量不能是 1 , 2 , ? ? , k 1,2,\cdots,k 1,2,?,k 中的任意一个,它们就再也不可能被选,它们就被排除了。而剩下未被排除的商店共有 O ( k log ? k ) O(k\log k) O(klogk) 个。注意过程中我们并没有得到 S i S_i Si? 中的商店只能恰好取 i i i 个物品之类的结论。

于是商店的总数缩减到了 O ( k log ? k ) O(k\log k) O(klogk) 个,时间复杂度降为 O ( k 2 log ? 2 k ) O(k^2\log ^2k) O(k2log2k)。预处理的部分视实现可以做到 O ( n log ? n ) O(n\log n) O(nlogn) O ( n log ? k ) O(n\log k) O(nlogk) O ( n ) O(n) O(n)

#include<bits/stdc++.h>

#define K 1010
#define N 2000010
#define ll long long
#define LNF 0x7ffffffffffffff
#define fi first
#define se second
#define pli pair<ll,int>
#define mk(a,b) make_pair(a,b)

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,k;
bool vis[N];
ll f[K],g[K],h[K];

vector<ll>sa[N];
vector<pli>v[K];

void solve(int ql,int qr,int vl,int vr)
{
	if(ql>qr) return;
	int mid=(ql+qr)>>1;
	h[mid]=LNF;
	int pos=-1;
	for(int i=vl;i<=vr;i++)
	{
		if(i<=k&&0<=mid-i&&mid-i<=k)
		{
			ll tmp=f[i]+g[mid-i];
			if(tmp<h[mid]) h[mid]=tmp,pos=i;
		}
	}
	assert(pos!=-1);
	solve(ql,mid-1,vl,pos);
	solve(mid+1,qr,pos,vr);
}

int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;i++)
	{
		int m=read();
		sa[i].resize(min(m+1,k+1));
		sa[i][0]=read();
		for(int j=1;j<=m;j++)
		{
			if(j<=k)
			{
				sa[i][j]=sa[i][j-1]+read();
				v[j].push_back(mk(sa[i][j],i));
			}
			else read();
		}
	}
	for(int i=1;i<=k;i++)
	{
		sort(v[i].begin(),v[i].end());
		int s=k/i;
		for(int j=0,tot=0;j<(int)v[i].size()&&tot<s;j++)
		{
			if(!vis[v[i][j].se])
			{
				vis[v[i][j].se]=1;
				tot++;
			}
		}
	}
	for(int i=1;i<=k;i++) f[i]=LNF/10;
	for(int i=1;i<=n;i++)
	{
		if(vis[i])
		{
			for(int j=0;j<(int)sa[i].size();j++) g[j]=sa[i][j]-sa[i][0];
			for(int j=(int)sa[i].size();j<=k;j++) g[j]=LNF/10;
			solve(0,k,0,k);
			for(int j=0;j<=k;j++) f[j]=min(f[j],sa[i][0]+h[j]);
		}
	}
	for(int i=1;i<=k;i++)
		printf("%lld ",f[i]);
	return 0;
}
/*
2 2	
1 5 6 
2 3 5 7
*/
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-03 16:22:02  更:2022-01-03 16:24:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:51:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码