2019hdu多校第七场h1007Getting Your Money Backc

题意:银行里有[x,y]的钱,你选择取i块钱,取钱成功花费手续费a,并取钱;取钱失败花费手续费b,无别的操作。你要将里面所有钱都取出来,而且得确信里面没钱。问最少手续费?

题解:
所谓确信里面没钱,有两种情况,假设当前已知区间 [ x , y ] [x,y] [x,y](x 不为0),一种就是取y元成功,结束;另一种就是取x+1元失败,那么下一步就是取x元成功,结束。
[ x , y ] [x,y] [x,y](x 为0)时,第一种相同,第二种为取1元失败,结束。

显而易见, [ x , y ] [x,y] [x,y](x不为0)元可转化为 [ 1 , y − x + 1 ] [1,y-x+1] [1,yx+1]的情况。
n 2 n^2 n2复杂度的dp式子显而易见不难推,分成取成功取失败两种情况,并对上面情况进行讨论:
d p [ 0 , x ] dp[0,x] dp[0,x]表示最多有为x元,左端点为0, d p [ 1 , x ] dp[1,x] dp[1,x]表示最多有x,左端点不为0。
d p [ 0 , x ] = m i n ( m a x ( d p [ 0 , i − 1 ] + b , d p [ 0 , x − i ] + a ) ) ( i ∈ [ 1 , x ] ) ; dp[0,x]=min(max(dp[0,i-1]+b,dp[0,x-i]+a))(i \in[1,x]); dp[0,x]=min(max(dp[0,i1]+b,dp[0,xi]+a))(i[1,x]);
d p [ 1 , x ] = m i n ( m a x ( d p [ 1 , i − 1 ] + b , d p [ 0 , x − i ] + a ) ) ( i ∈ [ 1 , x ] ) ; dp[1,x]=min(max(dp[1,i-1]+b,dp[0,x-i]+a))(i \in[1,x]); dp[1,x]=min(max(dp[1,i1]+b,dp[0,xi]+a))(i[1,x]);
初始值 d p [ 0 , 0 ] = 0 , d p [ 1 , 0 ] = a dp[0,0]=0,dp[1,0]=a dp[0,0]=0,dp[1,0]=a

对于这个,出题人题解是有二分做法,函数三分。因为其中有单调性,我利用单调性写的是线性的。因为从 x x x位变换到 x + 1 x+1 x+1位,最大值位置变换不会很大。(为什么?凭感觉,,要证太麻烦,,懒得补这坑,,不过其实我本来打算写个小小的退火,没想到直接过了)因此从上一个位置的最大值往两边搜索即可。

---------------------仔细一想,回来补一下单调性的证明(真繁琐呢)
只要证了 d p [ 0 , x ] dp[0,x] dp[0,x]的就可以, d p [ 1 , x ] dp[1,x] dp[1,x]的同理。用反证法来证吧。
对于 d p [ 0 , x + 1 ] , d p [ 0 , x ] dp[0,x+1],dp[0,x] dp[0,x+1],dp[0,x],假设 d p [ 0 , x ] dp[0,x] dp[0,x]的最大值位置为 m i mi mi,即 d p [ 0 , x ] = m a x ( d p [ 0 , m i − 1 ] + b , d p [ 0 , x − m i ] + a ) dp[0,x]=max(dp[0,mi-1]+b,dp[0,x-mi]+a) dp[0,x]=max(dp[0,mi1]+b,dp[0,xmi]+a),那么分类讨论 d p [ 0 , x + 1 ] dp[0,x+1] dp[0,x+1]

假设最大值同为 m i mi mi

  1. 那么 d p [ 0 , x + 1 ] = m a x ( d p [ 0 , m i − 1 ] + b , d p [ 0 , x + 1 − m i ] + a ) dp[0,x+1]=max(dp[0,mi-1]+b,dp[0,x+1-mi]+a) dp[0,x+1]=max(dp[0,mi1]+b,dp[0,x+1mi]+a)
    d p [ 0 , x + 1 ] = d p [ 0 , m i − 1 ] + b dp[0,x+1]=dp[0,mi-1]+b dp[0,x+1]=dp[0,mi1]+b时,显然 d p [ 0 , x ] dp[0,x] dp[0,x]也为这个值,因此单调不上升;

  2. d p [ 0 , x + 1 ] = d p [ 0 , x + 1 − m i ] + a dp[0,x+1]=dp[0,x+1-mi]+a dp[0,x+1]=dp[0,x+1mi]+a时,
    假设 d p [ 0 , x ] = d p [ 0 , m i − 1 ] + b dp[0,x]=dp[0,mi-1]+b dp[0,x]=dp[0,mi1]+b,已知 d p [ 0 , x + 1 ] = m a x ( d p [ 0 , x + 1 − m i ] + a , d p [ 0 , m i − 1 ] + b ) = d p [ 0 , x + 1 − m i ] + a > d p [ 0 , m i − 1 ] + b = d p [ 0 , x ] dp[0,x+1]=max(dp[0,x+1-mi]+a,dp[0,mi-1]+b)=dp[0,x+1-mi]+a>dp[0,mi-1]+b=dp[0,x] dp[0,x+1]=max(dp[0,x+1mi]+a,dp[0,mi1]+b)=dp[0,x+1mi]+a>dp[0,mi1]+b=dp[0,x],此时会变大;

  3. 假设 d p [ 0 , x ] = d p [ 0 , x − m i ] + a dp[0,x]=dp[0,x-mi]+a dp[0,x]=dp[0,xmi]+a,此时 d p [ 0 , x + 1 ] − d p [ 0 , x ] = d p [ x + 1 − m i ] − d p [ x − m i ] dp[0,x+1]-dp[0,x]=dp[x+1-mi]-dp[x-mi] dp[0,x+1]dp[0,x]=dp[x+1mi]dp[xmi],最差时一直迭代到 d p [ 0 , 1 ] 和 d p [ 0 , 0 ] dp[0,1]和dp[0,0] dp[0,1]dp[0,0],而已知 d p [ 0 , 1 ] > d p [ 0 , 0 ] dp[0,1]>dp[0,0] dp[0,1]>dp[0,0],所以这种情况仍会单调。

假设最大值不为 m i mi mi,设为 m j mj mj

  • d p [ 0 , x + 1 ] = m a x ( d p [ 0 , m j − 1 ] + b , d p [ 0 , x + 1 − m j ] + a ) dp[0,x+1]=max(dp[0,mj-1]+b,dp[0,x+1-mj]+a) dp[0,x+1]=max(dp[0,mj1]+b,dp[0,x+1mj]+a)
    已知 d p [ 0 , x ] &lt; = m a x ( d p [ 0 , m j − 1 ] + b , d p [ 0 , x − m j ] + a ) dp[0,x]&lt;=max(dp[0,mj-1]+b,dp[0,x-mj]+a) dp[0,x]<=max(dp[0,mj1]+b,dp[0,xmj]+a),这个与上面式子比较,又回到上面的情况。

综上所述, d p [ 0 , x ] dp[0,x] dp[0,x]单调不上升性证毕。

代码:

#include<bits/stdc++.h>
#include<algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include  <stdio.h>
#include   <math.h>
#include   <time.h>
#include   <vector>
#include   <bitset>
#include    <queue>
#include      <map>
#include      <set>
using namespace std;
typedef long long ll;
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((long long)(x).size())
#define mod Mod
const int maxn = 2e5 + 5;
    int x,y,a,b,T;
    ll dp[maxn],dp2[maxn];
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d",&x,&y,&a,&b);
        int n = y - x;
        dp[0] = 0;
        int dan = 1;   
        rep(i,1,n){
            dp[i] = max(dp[dan-1]+b,dp[i-dan]+a);
            int l = dan - 1,r = dan + 1;
            while(l){
                ll dpp = max(dp[l-1]+b,dp[i-l]+a);
                if(dpp < dp[i]){
                   dan = l;
                   dp[i] = dpp;
                   l --;
                }
                else break;
            }
            while(r<=i){
                ll dpp = max(dp[r-1]+b,dp[i-r]+a);
                if(dpp < dp[i]){
                   dan = r;
                   dp[i] = dpp;
                   r ++;
                }
                else break;
            }
        }
        if(x == 0){
            printf("%lld\n",dp[n]);
            continue;
        }
        else{
            dp2[0] = a;
            dan = 1;
            rep(i,1,n){
                dp2[i] = max(dp2[dan-1]+b,dp[i-dan]+a);
                int l = dan - 1,r = dan + 1;
                while(l){
                    ll dpp = max(dp2[l-1]+b,dp[i-l]+a);
                    if(dpp < dp2[i]){
                       dan = l;
                       dp2[i] = dpp;
                       l --;
                    }
                    else break;
                }
                while(r<=i){
                    ll dpp = max(dp2[r-1]+b,dp[i-r]+a);
                    if(dpp < dp2[i]){
                       dan = r;
                       dp2[i] = dpp;
                       r ++;
                    }
                    else break;
                }
            }
            printf("%lld\n",dp2[n]);
        }
    }
    return 0;
}
``

猜你喜欢

转载自blog.csdn.net/aiqiyizz/article/details/99415586