【SCOI2014】【BZOJ3598】方伯伯的商场之旅(数位dp)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3598

题意:

  对于一个数x,它含有一些小石子,每个石子的值为a[i](a[i]为x在k进制下的第i位),选一个石子的位置pos使得sum(a[i] * abs(i-pos))最小。 求出[L,R]中所有数这个值的和。

题解:

  对于一个数,我们枚举最优位置时,可以发现从i->i+1的变化为+pre[i]-suf[i+1](分别为前缀和与后缀和)。

  30%的暴力分,我们枚举[L,R]中的数,然后进行上述操作即可。

  那么100%的分呢?我们考虑将每一个数的位置设为1,答案为a[i]*(i-1),然后数位dp求出初始花费cost。 对于将位置i->i+1的变化,+前i个数 -后i+1个数。我们考虑枚举这个操作,并且求出进行这一操作后对于这些数共计会优多少。

  上面那些看不懂的话来看这里吧_(:з」∠)_。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <iostream>
 5 #define LL long long
 6 using namespace std;
 7 const int MaxN = 65;
 8 int u[MaxN], d[MaxN], LEN;
 9 LL l, r, k;
10 LL f[MaxN][2][2], g[MaxN][1600], ans[2333], sum[MaxN][2][2];
11
12 LL dp(int len, int up, int down){
13     if (!len) { sum[len][up][down] = 1; return 0; }
14     if (f[len][up][down]!= -1) return f[len][up][down];
15     LL ret = 0ll, num = 0ll;
16     int top = up ? u[len] : (int)k-1, bot = down ? d[len] : 0;
17     for (int i = bot; i <= top; i++){
18         int p1 = (i==top)&&up, p2 = i==bot&&down;
19         ret += dp(len-1, p1, p2) + i*(len-1)*sum[len-1][p1][p2];
20         num += sum[len-1][p1][p2];
21     }
22     f[len][up][down] = ret, sum[len][up][down] = num;
23     return ret;
24 }
25
26 LL calc(LL x, LL y){
27     int len = 0, len2 = 0;
28     while(x){
29         u[++len] = (int) (x%k);
30         x /= k;
31     }
32     while(y){
33         d[++len2] = (int) (y%k);
34         y /= k;
35     }
36     LEN = len;
37     return dp(len, 1, 1);
38 }
39
40 LL dfs(int len, int up, int down, int p, int s){
41     if (!len) return (LL)s;
42     if (!up && !down && g[len][s] != -1) return g[len][s];
43     LL ret = 0;
44     int top = up ? u[len] :(int)k-1, bot = down ? d[len] : 0;
45     for (int i = bot; i <= top; i++){
46         int x = (len >= p ? 1 : -1), c = i==top&&up, d = i==bot&&down;
47         x = x*i + s;
48         if (x < 0) break;
49         ret += dfs(len-1, c, d, p, x);
50     }
51     if (!up && !down) g[len][s] = ret;
52     return ret;
53 }
54
55 void Solve(){
56     memset(f, -1ll, sizeof(f));
57     LL ret = calc(r, l);
58     //cout<<ret<<endl;
59     LL dec = 0ll;
60     for (int i = 2; i <= LEN; i++){
61         memset(g, -1ll, sizeof(g)), dec += dfs(LEN, 1, 1, i, 0);
62     }
63     cout<<ret - dec;
64 }
65
66 int main(){
67     cin>>l>>r>>k;
68     Solve();
69     return 0;
70 }

时间: 2025-01-20 02:16:19

【SCOI2014】【BZOJ3598】方伯伯的商场之旅(数位dp)的相关文章

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

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3598 数位DP...东看西看:http://www.cnblogs.com/Artanis/p/3751644.html     https://www.cnblogs.com/MashiroSky/p/6399095.html 好巧妙的思路啊!这样统计的东西就变得很简单了: 好美的 dfs!数位DP用 dfs 好像能变得很清楚. 代码如下: #include<iostream> #in

「SCOI2014」方伯伯的商场之旅

「SCOI2014」方伯伯的商场之旅 题目描述 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 \(i\) 的人面前的第 \(j\) 堆的石子的数量,刚好是 \(i\) 写成 \(K\) 进制后的第 \(j\) 位. 现在方伯伯要玩一个游戏,商场会给方伯伯两个整数 \(L,R\).方伯伯要把位置在 \([L, R]\) 中的每个人的石子都合并成一堆石子.每次操作,他可以选择一个人面前的两堆石子,将其中的一堆中的某些石子移动到另一堆,代价

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

方伯伯的商场之旅 输入格式: 输入仅有1 行,包含3 个用空格分隔的整数L,R,K,表示商场给方伯伯的2 个整数,以及进制数 输出格式: 输出仅有1 行,包含1 个整数,表示最少的代价. 样例输入: 3 8 3 样例输出: 5 数据范围: 时间限制: 3s 空间限制: 64M 具体思路:数位DP 先假装所有数都转移到第一位上, 然后扫一下其他位,把对答案有益的加上 AC代码 #include<bits/stdc++.h> using namespace std; #define int lon

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

http://www.lydsy.com/JudgeOnline/problem.php?id=3598 (题目链接) 题意 Solution 原来这就是极水的数位dp,呵呵= =,感觉白学了.http://www.cnblogs.com/Artanis/p/3751644.html 首先我们考虑集结点设置第一位(最低位)上,数位dp计算出此时的代价. 如果将集结点往高位移动一位,那么此时代价会怎么变化呢,位置比集结点高的数位上的数它们的距离全部-1,位置比集结点低的数位上的数它们的距离全部+1

[SCOI2014]方伯伯的商场之旅

Description 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的第 j 位. 现在方伯伯要玩一个游戏,商场会给方伯伯两个整数 L,R.方伯伯要把位置在 [L, R] 中的每个人的石子都合并成一堆石子.每次操作,他可以选择一个人面前的两堆石子,将其中的一堆中的某些石子移动到另一堆,代价是移动的石子数量 * 移动的距离.商场承诺,方伯伯只要完成任务,就给他一些椰子,

bzoj 3598: [Scoi2014]方伯伯的商场之旅【数位dp】

参考了这个http://www.cnblogs.com/Artanis/p/3751644.html,好像比一般方法好写 大概思想就是先计算出把所有石子都合并到1位置的代价,这样显然有一些是不优的,然后再分别计算把合并到1的石子合并到p,能优化多少 这个计算就是枚举2到tot位,对于每一位计算挪到这位能被优化的数最多能被优化多少,因为合并点右移的代价是sum[w]-(sum[n]-sum[w]),所以只要这个为负数就退出即可 #include<iostream> #include<cst

【做题】方伯伯的商场之旅——枚举决策

这道题的数位dp是很显然的.然而,本题不仅要计数还要保证最优化,这使得我们难以得到一个简单的dp状态表示方式. 遗憾的是考虑dp状态数的直接减少是一个错误的思考方向.本人在此浪费了几个小时的时间. 注意到虽然是最优化,但决策数是非常少的,仅有O(logn)级别.同时,我们可以很容易地判断一个解是不是最优的. 于是,我们可以枚举最终合并到哪一位,然后就很容易了,本人是维护满足这个条件的数的个数和答案的和,这里就不详细讲了. 最后一个问题在于一个数可能在多个位置都是决策最优的.注意到它的充要条件是选

【BZOJ3594】【SCOI2014】 方伯伯的玉米田

显然可以看出这是一道DP,然后就开始定义状态... f[i][j]表示已经处理完i根玉米,拔高了j次,剩下的玉米的最大值. f[i][j] = max{f[x][y]+1}(x<i,y<=j,h[x]+y<=h[i]+j). 于是就可以用二维树状数组维护最大值了,第一维维护拔高次数,第二维维护拔高后的高度. 1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include

「SCOI2014」方伯伯的玉米田

动态规划+数据结构优化 每次操作区间的右端点一定为n,因为要尽量的让后面的数更大 记 f[i][k] 为以第i个玉米为结尾一共操作了k次的最长不下降序列的长度 因为每次操作右端点为n,左端点小于等于i 所以此时i的高度为 h[i] + k 则 f[i][k] = max(f[j][l]) + 1 // h[j] + l <= h[i] + k, j < i, l <= k 将每个状态 f[i][k] 可以表示为 (k, h[i] + k) // 操作次数,结尾高度 每次转移相当于取 (K