• 【洛谷3286】[SCOI2014] 方伯伯的商场之旅(数位DP)


    题目链接

    • 给定一个正整数 (k),编号为 (i) 的人面前的第 (j) 堆石子中的石子数恰好等于 (i)(k) 进制下的第 (j) 位的值。
    • 把某一个人面前的第 (x) 堆石子完全合并入第 (y) 堆石子需要的代价为 (x) 中的石子数 ( imes|x-y|)
    • 求将 ([L,R]) 中所有人面前的石子分别合并为一堆所需要的最小代价和。
    • (1le Lle Rle10^{15})(2le kle20)

    数位 DP 求负变化量

    对于一个人,我们的策略肯定选择 石子位置的中位数 作为最终的集合位置,但这样并不方便求解。

    考虑将最终的集合位置从最高位向最低位移动,在这一过程中代价的变化量逐渐增大,所以当代价变化量由负转正时就可以停止移动了,因为之后不可能再出现新的负变化量。

    用数位 DP 来实现对这一过程的维护。即,初始假设最终的集合位置在最高位,并求出所有人的代价和。然后,依次枚举每一个位置 (i),DP 求出最终集合位置从第 (i+1) 位移到第 (i) 位的所有负变化量之和,更新答案。

    具体地,对于每个 (i),用记忆化搜索实现,记录 (x,s) 两维状态表示处理完前 (x) 位后代价变化量为 (s) 即可。

    代码:(O(klog^4V))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Rg register
    #define RI Rg int
    #define Cn const
    #define CI Cn int&
    #define I inline
    #define W while
    #define V 5000
    #define LL long long
    using namespace std;
    int k,c,a[60],g[60];LL f[60][V<<1];
    I LL DP(CI x,CI s,CI fg=0)//记忆化搜索
    {
    	if(!x) return max(s,0);if(fg&&~f[x][s+V]) return f[x][s+V];LL t=0;
    	RI lim=fg?k-1:a[x];for(RI i=0;i<=lim;++i) t+=DP(x-1,s+g[x]*i,fg||(i^lim));return fg&&(f[x][s+V]=t),t;//枚举这一位填的数
    }
    I LL Calc(LL n)//计算小于等于n的答案
    {
    	if(!n) return 0;c=0;W(n) a[++c]=n%k,n/=k;RI j;for(j=1;j<=c;++j) g[j]=c-j;memset(f,-1,sizeof(f));LL t=DP(c,0);//分解;假设最终集合位置在最高位
    	for(RI i=c-1;i;memset(f,-1,sizeof(f)),t-=DP(c,0),--i) for(j=1;j<=c;++j) g[j]=j<=i?1:-1;return t;//求出最终集合位置从i+1移到i的负变化量之和
    }
    int main()
    {
    	LL L,R;return scanf("%lld%lld%d",&L,&R,&k),printf("%lld
    ",Calc(R)-Calc(L-1)),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    每周必写
    每周必写
    每周必写
    中国历史上成功的两人合作, 改进, 提高的例子
    每周必写(3)
    结对编程进度及自己的理解
    每周必写
    IT行业的“创新”、“模仿”
    工作时间内容,感想和思考
    周阅读内容
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3286.html
Copyright © 2020-2023  润新知