[SCOI2014] 方伯伯的商场之旅

Posted ysfac

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2014] 方伯伯的商场之旅相关的知识,希望对你有一定的参考价值。

题意:

有$10^{15}$个人,第i个人面前有$lceil log_{k}{i} ceil$堆石子,第j堆石子的数量为i写成k进制的第j位。

对于编号在$[L,R]$之间的人,你希望把每个人的石子合并成一堆。

移动一次石子的代价是$移动数量 imes 移动距离$,请你求出最小移动代价之和。

$L,Rleq 10^{15},2leq kleq 20$。

 

题解:

容易发现每个人的移动代价关于合并到哪一堆的函数是一个下凸的单峰函数。

那么我们其实就可以写一个类似于整体三分的东西。我写了结果调不出来了。

发现这题复杂度并不高,于是其实可以把整体三分改成直接枚举合并到哪一堆。

先求出一开始都合并到第一堆的答案,然后将合并堆逐渐右移,考虑代价的变化。

对于一个数x,设它在k进制下$[1,a]$位的数字和为$pre_{x,m}$,$[a,n]$位的数字和为$suf_{x,m}$。

那么每当合并堆从第i-1堆移动到第i堆时,x的代价就会增加$pre_{x,i-1}-suf_{x,i}$。

根据整体三分的思想,如果到第i堆时$pre_{x,i-1}-suf_{x,i}geq 0$,那么x这个数就被丢在第i-1位之前了,它的最优合并堆一定$<i$。

否则需要将总代价增加$pre_{x,i-1}-suf_{x,i}$(其实是减少),它的最优合并堆仍然$geq i$。

注意到如果一个数x在某一堆停止移动了,那么在后面的任何一堆它都满足$pre_{x,i-1}-suf_{x,i}geq 0$,所以无需特判。

我们现在只需要算这两个东西:

  1. 令$x={a_1 a_2 cdots a_n}_{(k)}$,求$sum limits_{x=L}^{R}{a_2 + 2a_3 +cdots +(n-1)a_n}$。
  2. 对于第p堆,求$sum limits_{x=L}^{R}{min(pre_{x,p-1}-suf_{x,p},0)}$。

容易想到数位dp就是用来求形如$sum limits_{x=L}^{R}{val_{x}}$且$val_{x}$仅与数位数字有关的式子,于是数位dp即可。

复杂度$O(300(log_{k}{R})^{2}k)$。(对于所有的数位dp,其复杂度为$O(状态数 imes 转移数)$)

 

套路:

  • 形如$sum limits_{x=L}^{R}{val_{x}}$且$val_{x}$仅与数位数字有关的式子$ ightarrow$数位dp。
  • 求若干个单峰函数的极值之和$ ightarrow$整体三分。

 

代码:

技术图片
#include<bits/stdc++.h>
#define maxn 65
#define maxm 3005
#define inf 0x7fffffff
#define ll long long
#define rint register ll
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
ll k,f[maxn][2][2],g[maxn][maxm][2],dig[maxn];

inline ll read(){
    ll x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}

inline void dfs1(ll n,ll ise){
    if(n==0) f[n][ise][0]=1,f[n][ise][1]=0;
    if(f[n][ise][0]==-1){
        f[n][ise][0]=f[n][ise][1]=0;
        for(ll i=0;i<=(ise?dig[n]:(k-1));i++){
            ll nise=ise&(i==dig[n]);
            dfs1(n-1,nise),f[n][ise][0]+=f[n-1][nise][0];
            f[n][ise][1]+=f[n-1][nise][1]+f[n-1][nise][0]*i*(n-1); 
        }
    }
}

inline void dfs2(ll n,ll p,ll sum,ll ise){
    if(n==0) g[n][sum+250][ise]=max(sum,0ll);
    if(g[n][sum+250][ise]==-1){
        g[n][sum+250][ise]=0;
        for(ll i=0;i<=(ise?dig[n]:(k-1));i++){
            ll nsum=(n<p)?(sum-i):(sum+i);
            ll nise=ise&(i==dig[n]);
            dfs2(n-1,p,nsum,nise);
            g[n][sum+250][ise]+=g[n-1][nsum+250][nise];
        }
    }
}

inline ll solve(ll x){
    ll tp=x,n=0;
    while(tp) dig[++n]=tp%k,tp/=k;
    memset(f,-1,sizeof(f));
    dfs1(n,1); ll cost=f[n][1][1];
    for(ll i=2;i<=n;i++){
        memset(g,-1,sizeof(g));
        dfs2(n,i,0,1),cost-=g[n][250][1];
    }
    return cost;
}

int main(){
    ll l=read(),r=read();k=read();
    cout<<solve(r)-solve(l-1)<<endl;
    return 0;
}
方伯伯的商场之旅

 

以上是关于[SCOI2014] 方伯伯的商场之旅的主要内容,如果未能解决你的问题,请参考以下文章

[SCOI2014]方伯伯的商场之旅

bzoj3598: [Scoi2014]方伯伯的商场之旅

bzoj3598 [Scoi2014]方伯伯的商场之旅

[SCOI2014]方伯伯的商场之旅

[SCOI2014] 方伯伯的商场之旅

bzoj3598 Scoi2014—方伯伯的商场之旅