首页 > 其他分享 >【XSY3535】购物(决策单调性优化DP,分治,结论,背包)

【XSY3535】购物(决策单调性优化DP,分治,结论,背包)

时间:2022-10-30 12:57:43浏览次数:43  
标签:log 商店 int 分治 单调 sa define DP XSY3535

题面

购物

题解

决策单调性全忘了……

先考虑暴力怎么做,我们可以设 \(f_{i,j}\) 表示前 \(i\) 个商店买了 \(j\) 件物品的最小代价,然后有转移:

\[f_{i,j}=\min_{k=0}^j(f_{i-1,k}+sa_{i,j-k}) \]

其中 \(sa_{i,j}\) 表示 \(a_{i,*}\) 的前缀和,其中 \(sa_{i,0}=0,sa_{i,1}=a_{i,0}+a_{i,1},sa_{i,2}=a_{i,0}+a_{i,1}+a_{i,2},\cdots\)。

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

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

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

在这里插入图片描述

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

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

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

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

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

再看回这一题:

\[f_{n,k}=\min_{i+j=k}(f_{n-1,i}+sa_{n,j}) \]

观察到式子中 \(f_{n-1,*}\) 和 \(sa_{n,*}\) 是单调不降的,\(sa_{n,*}\) 的差分数组 \(\Delta sa_{n,*}\) 第二位及之后都是单调不降的,但是却有可能 \(\Delta sa_{n,1}>\Delta sa_{n,2}\)。

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

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

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

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

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

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

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

于是商店的总数缩减到了 \(O(k\log k)\) 个,时间复杂度降为 \(O(k^2\log ^2k)\)。预处理的部分视实现可以做到 \(O(n\log n)\)、\(O(n\log k)\) 或 \(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
*/

标签:log,商店,int,分治,单调,sa,define,DP,XSY3535
From: https://www.cnblogs.com/ez-lcw/p/16841018.html

相关文章

  • 【XSY3513】Multiple of Nine(状压DP)
    题意:转化后变为:给一张\(n\)个点的图,你需要给每个点染上\([1,k]\)中的某个颜色,图上有\(m\)条边,每条边\((u,v)\)有两种边权\(w_1\)(当\(u,v\)颜色相同时)和\(w_2\)......
  • (美化)WordPress网站添加自定义字体
    背景通过CSS属性@font-face和font-family可以实现加载自定义webfont,改变网页字体,实现美化效果。1.引用字体文件出于版权风险考虑,尽量使用免费可商用的字体作为webfont。本......
  • wordpress网站主题安装教程
    前面已经搭建好了网站,但是默认的页面比较简陋,我们需要更改一下外观现在我们安装新的主题外观,使网站更加的好看下载主题https://www.lovestu.com/corepress-free可以使......
  • 【XSY3270】Domino Colorings(轮廓线dp,状压)
    若已经知道了每个格子的颜色,我们可以用轮廓线DP(类似插头DP)判断棋盘是否能被多米诺骨牌填满,设\(dp[S]\)表示是否存在某种填法使得轮廓线每个位置是否被填的状态为\(S\)......
  • 【XSY3241】暴风士兵(stormtrooper)(多项式分治,期望)
    设一个人被扣了\(i\)滴血的概率为\(p_i\),设\(c_i=exp-i\)且只有\(c_0,c_1,\cdots,c_{exp}\)有值,那么题目就是在问\(\sum\limits_{i=0}^{exp}c_ip_i\)。我们设\(p......
  • 【XSY3338】game(期望,点分治,FFT)
    题面game题解首先可以看出“等概率选连通块->连通块内等概率选点”相当于“全局等概率选点”。一开始感觉无从下手,但是题目中还是给了一点提示。题目让我们输出答......
  • 【XSY3331】东非大裂谷(结论,DP)
    一般这种“分段,求每段极值和的最大值”的题都有两个结论:一段的最大值和最小值一定是该段的两个端点。证明:如果不是的话:那么我们显然可以把最小值和最大值所在位置之......
  • 【XSY2444】【BZOJ4042】【CERC2014】【luogu4757】Parades(树形dp+状压dp)
    题面Description从前有个A国,它有\(n\)个城市和\(n-1\)条道路。每条路连接两个城市。城市之间两两可达。每个城市与不超过10条道路相连。现在给出\(m\)条路径,要求从这些......
  • 【XSY2423】跳蚤(根号分治)
    题面题解神奇的分类讨论。首先注意到每次所有跳蚤都只会往右跳,也就是说只要某一只跳蚤跳出了\(\max(r_i)\)它就不会再有贡献了。(和火神的鱼类似)令\(R=\max(r_i)......
  • 【XSY1976】【BZOJ2286】【SDOI2011】消耗战(虚树,dp)
    这题的dp思想还是比较容易想的,关键是如何保证时间复杂度,这时就用到了虚树的技巧。1.虚树是什么?(虚树的性质)不妨设现在询问给出了\(k\)个点,我们命名这些节点为关键节点。......