凸函数相关问题

Published: by Creative Commons Licence

  • Tags:

基础知识

  • 一个函数f是上凸函数,当且仅当对于任意a<c,记录b=(a+c)/2,有2f(b)f(a)+f(c)
  • 一个函数f是下凸函数,当且仅当对于任意a<c,记录b=(a+c)/2,有2f(b)f(a)+f(c)
  • 如果函数f在定义域上二次可微,且f0,则f是下凸函数,若f0,则f是上凸函数。
  • 函数ax是下凸函数,如果a0
  • 函数lnx是上凸函数,exp(x)是下凸函数。
  • 函数xn[0,+)上,若0n1,则为上凸函数,若x1,则为下凸函数。

命题1:如果函数f和函数g都是上凸(下凸)函数,则它们的和f+g也是上凸(下凸)函数。

证明:略。

命题2:如果函数f和函数g都是上凸函数,则它们的和min(f,g)也是上凸函数。

证明:略。

命题3:如果函数f和函数g都是下凸函数,则它们的和max(f,g)也是下凸函数。

证明:略。

命题4:如果函数fg是上凸(下凸)函数,且f递增,则f(g)也是上凸(下凸)函数。

证明:略。

最大和问题

题目1:给定m个线性函数f1,,fm,其中fi(x)=aix+bi,现在我们希望为m个非负整数未知变量x1,,xm赋值,且要求满足maxmi=1xi=n,在满足约束条件下,要求ni=1fi(xi)尽可能大。

我们可以这样来理解这个问题,首先我们有m个可投资对象和n个资源,且已经获利mi=1bi,接下来如果我们为第i个可投资对象每投入一单位资源,那么就能获利ai,问最大获利多少。

这个自然是将所有资源都砸在ai最大的可投资对象上了。

题目2:给定m个函数f1,,fm,且每个函数的成像都构成一个上凸包,现在我们要求为m个非负整数未知变量x1,,xm赋值,且要求满足mi=1xi=n,在满足约束条件下,要求ni=1fi(xi)尽可能大。其中1m,n105

利用题目1的方式,我们来试图重新解读问题。首先我们有m个可投资对象和n个资源,且已经获利mi=1fi(0),接下来如果我们为第i个可投资对象每投入一单位资源,那么就能获利fi(x+1)fi(x)x是已经向第i个可投资对象投入的资源总量),问最大获利多少。

我们会发现由于所有的函数都是上凸包,因此对于任意idi(x+1)=fi(x+1)fi(x)是非严格递减函数。考虑到di(1)di(2),因此在最终结果中,如果选择di(x+1)那么我们必定也会选择di(x),因此我们可以将所有可选的收益一开始就全部展开di(x),现在我们要做的就是从di(x)中选择正好n个元素,且元素之和最大。这个步骤自然我们会选择使用贪心算法来完成。

现在回到问题,如果我们把所有方案都展开,那么可能会有nm个选择,这样太多了,但是由于我们在取得di(x)之前是不会考虑di(x+1)的,因此我们可以对每个i,仅考虑x最小且未被选择的di(x)。实际操作中,我们只需要维护一个大小为m的大根堆即可,当我们将di(x)弹出的同时,将di(x+1)加回即可,总的时间复杂度为O(nlog2m)

提供一道SGU的问题

题目3:给定m个函数f1,,fm,且每个函数的成像都构成一个上凸包,现在我们要求为m个非负整数未知变量x1,,xm赋值,且要求满足mi=1xi=n,在满足约束条件下,要求ni=1fi(xi)尽可能大。其中1m105,1n1018

这个问题是今天比赛的一道题目学到的。由于是上凸包,因此我们可以用三分算法为每个函数找到其极值点(在非负整数定义域下),记fi的极值点在pi处取到。

分两种情况讨论,如果nmi=1pi,那么我们可以断定一定有xipi,否则对应的就有xipi

如果是nmi=1pi的情况。记di(x)=fi(x)fi(x1)称为函数fi在点x处的增量。很显然最优解中,采用的最小增量一定是最大的,我们可以通过二分法找到这个最小增量,这里的时间复杂度为O(n(log2M)2),其中M是数据范围。找到最小增量δ后,我们将xi设置为fi增量大于等于δ的整数点数目(不包括0)。那么此时可能会有mi=1xi>n的情况出现,我们可以保证所有函数增量大于δ的整数点都会被保留(否则为什么要使用增量为δ的点呢?),而增量为δ的点可以删除一部分,来满足mi=1xi>n,这一部分的时间复杂度为O(m)

对于nmi=1pi的情况,与上面的方法类似。

最后总的时间复杂度为O(m(log2M)2)

提供一道题目

题目4:给定n个非严格递增数组a1,a2,,an,长度分别为t1,,tn。之后要求执行正好m次操作,每次操作选择一个非空的数组头,并且删除数组头部元素。要求m次操作后删除的元素总和最大。输入满足1n,m3000,且mni=1ti106,每个数组元素在0109之间。

一般的DP做法时间复杂度为O(nmni=1ti),太慢了。

很显然我们最多只会有一个数组的元素是部分取走的。因此就得出了我们的思路,一种预处理前后缀的做法的时间复杂度为O(nm2+ni=1ti),还是不够好。

这里我们可以神奇的套上分治。类似与并行二分,我们可以将要处理的数组分为两部分,之后在左边的数组上暴力计算DP,并在递归处理右部分的时候作为初始值下传。可以发现抵达叶子(区间只有一个元素)的时候,这时候其余元素都被处理到了。

树的每一层的时间复杂度都是O(nm),最后一层的时间复杂度为O(ni=1ti)。因此总的时间复杂度为O(nmlog2n+ni=1ti)

提供一道题目

并且由于背包问题中交换商品顺序不影响结果,因此可以用可撤销队列来做,时间复杂度也是O(nmlog2n+ni=1ti)

题目5:给定m个函数f1,,fm,且每个函数的成像都构成一个上凸包,且每个函数的值域都是正数,现在我们要求为m个非负整数未知变量x1,,xm赋值,且要求满足mi=1xi=n,在满足约束条件下,要求ni=1fi(xi)尽可能大。其中1m105,1n1018。输出最大可能的乘积,结果对P取模。

我们希望ni=1fi(xi)最大,等价于希望ni=1lnfi(xi)最大。考虑到lnfi也是个上凸包,因此我们可以用问题3的方式找到每个函数的赋值方案,之后算出真实的乘积即可。时间复杂度为O(nlog2mlog2M)