「SCOI2014」方伯伯的商场之旅

「SCOI2014」方伯伯的商场之旅

题目描述

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

现在方伯伯要玩一个游戏,商场会给方伯伯两个整数 \(L,R\)。方伯伯要把位置在 \([L, R]\) 中的每个人的石子都合并成一堆石子。每次操作,他可以选择一个人面前的两堆石子,将其中的一堆中的某些石子移动到另一堆,代价是移动的石子数量\(\times\)移动的距离。商场承诺,方伯伯只要完成任务,就给他一些椰子,代价越小,给他的椰子越多。所以方伯伯很着急,想请你告诉他最少的代价是多少。

\(1≤L≤R≤10^{15}, 2≤K≤20\)。

解题思路 :

首先考虑一下对于某一个数如何求出其合并成一堆的代价,观察发现,最终答案的形态一定可以转化成所有数位都移到某一位

那么问题就转化为找出一个数位,使得其他数位移动到它的总代价最小,可以直接带权中位数求解

但实际上,带权中位数在数位 \(dp\) 的过程中状态不好表示,不妨再多考虑一下子问题解法的由来

考虑一下带权中位数 \(p\) ,其必然满足 \(val_p + \sum_{i=1}^{p-1} val_i \geq \sum_{i=p+1}^{n}\) ,反之同理,也就说,其无论往左移动或者往右移动都不会更优了

我们不妨先假设初始的 \(p = 1\) ,那么就只需要考虑 \(p\) 往右移动到 \(p+1\) 新增的代价了,显然是 \(\sum_{i=1}^{p} val_i - \sum_{i=p+1}^{n} val_i\)

此时如果代价 \(< 0\) 那么说明往右移动会更优,当某一时刻代价 \(\geq 0\) 的时候说明 \(p\) 既不能往右移动也不能往左移动了,此时其是带权中位数

也就是说,我们可以让所有数先移动到 \(1\) ,然后算出每一个 \(p\) 向右移动到 \(p+1\) 的代价,然后把所有 \(<0\) 的代价加上即可

具体实现的话就是一个比较简单的数位 \(dp\) ,考虑分两步计算:

\(f[i][0/1]\) 表示前 \(i\) 个数位,之前是否是上界的前缀的数全部移到第一位的总代价,枚举数位转移即可

对于每一个 \(p\in[1,len]\) ,算出 \(g[i][sum][0/1]\) 表示前 \(i\) 个数位,满足 \(\sum_{i=1}^{p} val_i - \sum_{i=p+1}^{n} val_i = sum\) 的数的个数,也是简单的枚举数位转移即可

注意在前导 \(0\) 的处理上,前导 \(0\) 不能被计算到距离里面,可以考虑每次只做恰好等于 \(n\) 位的数,多拿几个上界做几次,也可以加细节判掉,总复杂度是 \(O(log^3nK)\)

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}

#define int ll

const int zzd = 401;

int f[25][2], ss[25][2], g[25][1005][2], s[25], tmp[25], L, R, bs, lim, ans, ans2;

inline int Getcost(){
    int res = 0; memset(f, 0, sizeof(f)), memset(ss, 0, sizeof(ss));
    f[1][0] = s[1] - 1, f[1][1] = 1;
    for(int i = 2; i <= lim; i++){
        for(int j = 0; j < bs; j++){
            f[i][0] += f[i-1][0];
            ss[i][0] += ss[i-1][0] + f[i-1][0] * (i - 1) * j;
        }
        for(int j = 0; j < s[i]; j++){
            f[i][0] += f[i-1][1];
            ss[i][0] += ss[i-1][1] + f[i-1][1] * (i - 1) * j;
        }
        f[i][1] += f[i-1][1];
        ss[i][1] += ss[i-1][1] + f[i-1][1] * s[i] * (i - 1);
    }
    res += ss[lim][0] + ss[lim][1];
    return res;
}

inline int solve(int num){
    lim = 0; while(num) tmp[++lim] = num % bs, num /= bs;
    for(int i = 1; i <= lim; i++) s[i] = tmp[lim-i+1];
    int cost = Getcost();
    for(int p = 1; p <= lim; p++){
        memset(g, 0, sizeof(g)), g[1][zzd-s[1]][1] = 1;
        for(int i = 1; i < s[1]; i++) g[1][zzd-i][0] = 1;
        for(int i = 2; i <= lim; i++)
            for(int j = -400; j <= 400; j++){
                int sgn = i <= p ? 1 : -1;
                for(int k = 0; k < bs; k++) g[i][j+zzd][0] += g[i-1][j+sgn*k+zzd][0];
                for(int k = 0; k < s[i]; k++) g[i][j+zzd][0] += g[i-1][j+sgn*k+zzd][1];
                g[i][j+zzd][1] += g[i-1][j+sgn*s[i]+zzd][1];
            }
        for(int j = 1; j <= 400; j++) cost -= (g[lim][j+zzd][0] + g[lim][j+zzd][1]) * j;
    }
    return cost;
}

inline int calc(int x){
    int num = x, n = 0, ans = 0;
    while(num) ++n, num /= bs;
    ans += solve(x); int base = 0;
    for(int i = 1; i < n; i++)
        base = base * bs + bs - 1, ans += solve(base);
    return ans;
}

signed main(){
    read(L), read(R), read(bs);
    cout << calc(R) - calc(L - 1);
    return 0;
}

原文地址:https://www.cnblogs.com/mangoyang/p/9574584.html

时间: 2024-11-11 05:13:59

「SCOI2014」方伯伯的商场之旅的相关文章

「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

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

[SCOI2014]方伯伯的商场之旅

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

【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]中的数,然

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

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

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)级别.同时,我们可以很容易地判断一个解是不是最优的. 于是,我们可以枚举最终合并到哪一位,然后就很容易了,本人是维护满足这个条件的数的个数和答案的和,这里就不详细讲了. 最后一个问题在于一个数可能在多个位置都是决策最优的.注意到它的充要条件是选

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

【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