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

Time Limit: 30 Sec  Memory Limit: 64 MB
Submit: 449  Solved: 254
[Submit][Status][Discuss]

Description

方伯伯有一天去参加一个商场举办的游戏。商场派了一些工作人员排成一行。每个人面前有几堆石子。说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的第 j 位。
现在方伯伯要玩一个游戏,商场会给方伯伯两个整数 L,R。方伯伯要把位置在 [L, R]
中的每个人的石子都合并成一堆石子。每次操作,他可以选择一个人面前的两堆石子,将其中的一堆中的某些石子移动到另一堆,代价是移动的石子数量 *
移动的距离。商场承诺,方伯伯只要完成任务,就给他一些椰子,代价越小,给他的椰子越多。所以方伯伯很着急,想请你告诉他最少的代价是多少。
例如:10 进制下的位置在 12312 的人,合并石子的最少代价为:
1 * 2 + 2 * 1 + 3 * 0 + 1 * 1 + 2 * 2 = 9
即把所有的石子都合并在第三堆

Input

输入仅有 1 行,包含 3 个用空格分隔的整数 L,R,K,表示商场给方伯伯的 2 个整数,以及进制数

Output

输出仅有 1 行,包含 1 个整数,表示最少的代价。

Sample Input

3 8 3

Sample Output

5

HINT

1 < =  L < =  R < =  10^15, 2 < =  K < =  20

Source

一眼数位DP,但是具体实现感觉非常难以理解。

主要思路是:先默认每个人都将式子移到最低的那一位上去,然后从2开始枚举如果将其中一些人的石子从i-1移到i最终结果会优多少。

第一个DP就是普通的数位DP,但是第二个DP就有一个很难处理的问题:如何确定到底那些人的石子可以(或需要)从i-1移到i,因为每个人最终所选的那一位都不同。

这里有一种新型的记忆化搜索,dfs(i,sum,lim)表示(从高到低)前i位将(那些可以或需要移动的)人移动,且前i位已经变优了sum,所能得到的最终解(也就是最后最多能变优多少)。一般记搜都是形如dfs(i)+=dfs(i+1)+f(i)的(最终返回的sum),但这种记搜是dfs(i,sum,lim)+=dfs(i+1,sum+f[i],lim')(最终返回的仍然是sum,只是在递归底层被处理过的sum)。也就是说,普通记搜记录的是这个状态到目标状态(递归底层)的信息,而这种记录的是初始状态到这个状态的信息。

这种记搜实际上不应该从DP的角度去理解,而是应该从搜索的角度,实际上就是一个记录了中间状态(sum)的搜索,在底层进行处理。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define ll long long
using namespace std; int k,num[];
ll l,r,len,f[][**][]; ll dfs1(int pos,int sum,bool lim){
if (pos>len) return sum;
if (f[pos][sum][lim]!=-) return f[pos][sum][lim];
ll res=; int end=(lim?num[pos]:k-);
rep(i,,end) res+=dfs1(pos+,sum+i*(pos-),lim && (i==end));
return f[pos][sum][lim]=res;
} ll dfs2(int pos,int sum,int m,bool lim){
if (pos>len) return max(sum,);
if (f[pos][sum][lim]!=-) return f[pos][sum][lim];
ll res=; int end=(lim?num[pos]:k-);
rep(i,,end) res+=dfs2(pos+,sum+((pos<m)?-i:i),m,lim && (i==end));
return f[pos][sum][lim]=res;
} ll solve(ll n){
len=; while (n) num[++len]=n%k,n/=k;
reverse(num+,num+len+);
memset(f,-,sizeof(f));
ll res=dfs1(,,);
rep(i,,len) memset(f,-,sizeof(f)),res-=dfs2(,,i,);
return res;
} int main(){
freopen("bzoj3598.in","r",stdin);
freopen("bzoj3598.out","w",stdout);
scanf("%lld%lld%d",&l,&r,&k);
printf("%lld\n",solve(r)-solve(l-));
return ;
}

[BZOJ3598][SCOI2014]方伯伯的商场之旅(数位DP,记忆化搜索)的更多相关文章

  1. bzoj 3598 [Scoi2014]方伯伯的商场之旅——数位dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3598 TJ:https://www.cnblogs.com/Zinn/p/9351218.h ...

  2. BZOJ3598 SCOI2014方伯伯的商场之旅(数位dp)

    看到数据范围就可以猜到数位dp了.显然对于一个数最后移到的位置应该是其中位数.于是考虑枚举移到的位置,那么设其左边和为l,左右边和为r,该位置数为p,则需要满足l+p>=r且r+p>=l. ...

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

    数位dp,我们肯定枚举集合的位置,但是如果每次都重新dp的话会很麻烦,所以我们可以先钦定在最低位集合,dp出代价,然后再一步步找到正确的集合点,每次更改的代价也dp算就好了. #include < ...

  4. 2019.03.28 bzoj3598: [Scoi2014]方伯伯的商场之旅(带权中位数+数位dp)

    传送门 题意咕咕咕自己读吧挺简单的 思路: 由带权中位数的性质可以得到对于每个数放在每个二进制位的代价一定是个单调或者单峰函数,因此我们先把所有的数都挪到第一个位置,然后依次向右枚举峰点(极值点)把能 ...

  5. bzoj 3598 [ Scoi 2014 ] 方伯伯的商场之旅 ——数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3598 数位DP...东看西看:http://www.cnblogs.com/Artanis/ ...

  6. 洛谷P3286 [SCOI2014]方伯伯的商场之旅

    题目:洛谷P3286 [SCOI2014]方伯伯的商场之旅 思路 数位DP dalao说这是数位dp水题,果然是我太菜了... 自己是不可能想出来的.这道题在讲课时作为例题,大概听懂了思路,简单复述一 ...

  7. 【bzoj3598】: [Scoi2014]方伯伯的商场之旅

    Description 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的 ...

  8. 【bzoj3598】 Scoi2014—方伯伯的商场之旅

    http://www.lydsy.com/JudgeOnline/problem.php?id=3598 (题目链接) 题意 Solution 原来这就是极水的数位dp,呵呵= =,感觉白学了.htt ...

  9. [SCOI2014]方伯伯的商场之旅

    Description 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的 ...

随机推荐

  1. XMLHttpRequest 整理

    看了SF 上的一篇文章感触颇深:你真的会使用XMLHttpRequest吗? 在这我写上我读后的笔记: <!DOCTYPE html> <html lang="en&quo ...

  2. Java生成验证码简记

    验证码定义 验证码(captcha):是一种区分用户是计算机还是人的公共全自动程序. 作用:可以防止恶意破解密码.刷票.灌水,有效防止对某一个特定注册用户用特定程序进行暴力破解的登录尝试. 验证码交互 ...

  3. 【洛谷 P4542】 [ZJOI2011]营救皮卡丘(费用流)

    题目链接 用最多经过\(k\)条经过\(0\)的路径覆盖所有点. 定义\(ds[i][j]\)表示从\(i\)到\(j\)不经过大于\(max(i,j)\)的点的最短路,显然可以用弗洛伊德求. 然后每 ...

  4. Kali设置代理

    原文:Kali-linux设置ProxyChains ProxyChains是Linux和其他Unices下的代理工具.它可以使任何程序通过代理上网,允许TCP和DNS通过代理隧道,支持HTTP.SO ...

  5. C++类型转换 -- 由其他类型转换到自定义类型

    由其他类型转换到自定义类型 由其他类型(如int,double)向自定义类的转换是由构造函数来实现,只有当类的定义和实现中提供了合适的构造函数,转换才能通过. /******************* ...

  6. 在新版linux上编译老版本的kernel出现kernel/timeconst.h] Error 255

    在使用ubuntu16.4编译Linux-2.6.31内核时出现这样的错误 可以修改timeconst.pl的内容后正常编译. 以下是编译错误提示的内容: Can't use 'defined(@ar ...

  7. STL中heap相关函数

    heap并不是属于STL中的containers,而是在<algorithm>下提供了相关的函数 make_heap,sort_heap,pop_heap,push_heap 函数的说明: ...

  8. jquery 通过 live() 方法附加的事件处理程序适用于匹配选择器的当前及未来的元素(比如由脚本创建的新元素)

    jquery 通过 live() 方法附加的事件处理程序适用于匹配选择器的当前及未来的元素(比如由脚本创建的新元素) $("ul").append("<li cla ...

  9. POJ 1386 Play on Words(单词建图+欧拉通(回)路路判断)

    题目链接:http://poj.org/problem?id=1386 题目大意:给你若干个字符串,一个单词的尾部和一个单词的头部相同那么这两个单词就可以相连,判断给出的n个单词是否能够一个接着一个全 ...

  10. csu 1756(数论+去重)

    Prime Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 84  Solved: 12[Submit][Status][Web Board] Descr ...