[SCOI2014]方伯伯的商场之旅

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 个整数,以及进制数

HINT

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

Solution

说白了,这个题就是给了L~R的数,每个数的每个数位是一堆石子,把这堆石子合成一个位置,求总的最小代价。

法一:GZZ法

发现,对于一个数字P,假设钦定最终合并位置是p,

调整的时候,p向左移动一位,代价变化是p及右边所有的数位和-p左边所有数位和。

p向右移动一位,代价变化是p及左边所有数位和-p右边所有数位和。

设最优的位置的数字是x,位置是p,p左边数位和是a,右边是b

那么,一定有不等式:x+a-b>=0 ; x+b-a>=0 就是说,x不论往左往右移动,代价的变化总是增大的。

即:-x<=a-b<=x

所以,如果知道最终填的a-b,和x,p,就可以判断这个p位置填x是不是左边a,右边b的最优解了。

枚举p,x;

伪代码:(cnt是最高位,进制用m,填数用k)

for(p=1~cnt)

for(x=0~m-1)

for(i=cnt~1)

   for(a-b=-200~+200)

  设f[i][a-b][0/1]表示,填完第i位,a-b的值,有没有限制情况下,所有符合情况的数移动到p位置所花费的代价。

g[i][a-b][0/1]表示,f的方案数,即满足情况的数的个数,方便转移。

if(i==p){

    

    continue;

  }

for(k=0;k<m;k++){

    if(i<p)

    else

  }

 在i循环完之后,

 for(a-b=-200~+200)

if(-x<=a-b<x) ret+=f[1][a-b][0/1]

 注意这里是<=和<,因为可能一个数字有两个位置都是最优的合并位置,只能算一遍。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=70;
const int M=22;
const int fix=201;
const int up=402;
ll f[N][405][2];
ll g[N][405][2];
ll L,R;
int m;
ll ansl,ansr;
int a[N],cnt;
ll wrk(){
    ll ret=0;
    for(int p=1;p<=cnt;p++){
       for(int x=0;x<m;x++){
        memset(f,0,sizeof f);
        memset(g,0,sizeof g);
        g[cnt+1][fix][1]=1;
        for(int i=cnt;i>=1;i--){
            for(int j=0;j<=up;j++){
                    if(i==p){
                        if(x<a[i]){
                            if(g[i+1][j][0]) g[i][j][0]+=g[i+1][j][0],f[i][j][0]+=f[i+1][j][0];
                            if(g[i+1][j][1]) g[i][j][0]+=g[i+1][j][1],f[i][j][0]+=f[i+1][j][1];
                        }
                        else if(x==a[i]){
                            g[i][j][1]+=g[i+1][j][1],f[i][j][1]+=f[i+1][j][1];
                            g[i][j][0]+=g[i+1][j][0],f[i][j][0]+=f[i+1][j][0];
                        }
                        else{
                            g[i][j][0]+=g[i+1][j][0],f[i][j][0]+=f[i+1][j][0];
                        }
                        continue;
                    }

                for(int k=0;k<m;k++){
                    if(i>p){//before
                        if(j+k>up) continue;

                        if(k<a[i]){
                            g[i][j+k][0]+=g[i+1][j][0],f[i][j+k][0]+=f[i+1][j][0]+(i-p)*k*g[i+1][j][0];
                            g[i][j+k][0]+=g[i+1][j][1],f[i][j+k][0]+=f[i+1][j][1]+(i-p)*k*g[i+1][j][1];
                        }
                        else if(k==a[i]){
                            g[i][j+k][0]+=g[i+1][j][0],f[i][j+k][0]+=f[i+1][j][0]+(i-p)*k*g[i+1][j][0];
                            g[i][j+k][1]+=g[i+1][j][1],f[i][j+k][1]+=f[i+1][j][1]+(i-p)*k*g[i+1][j][1];
                        }
                        else{
                            g[i][j+k][0]+=g[i+1][j][0],f[i][j+k][0]+=f[i+1][j][0]+(i-p)*k*g[i+1][j][0];
                        }
                    }
                    else{//after
                        if(j-k<0) continue;

                        if(k<a[i]){
                            f[i][j-k][0]+=f[i+1][j][0]+g[i+1][j][0]*(p-i)*k,g[i][j-k][0]+=g[i+1][j][0];
                            f[i][j-k][0]+=f[i+1][j][1]+g[i+1][j][1]*(p-i)*k,g[i][j-k][0]+=g[i+1][j][1];
                        }
                        else if(k==a[i]){
                            f[i][j-k][0]+=f[i+1][j][0]+g[i+1][j][0]*(p-i)*k,g[i][j-k][0]+=g[i+1][j][0];
                            f[i][j-k][1]+=f[i+1][j][1]+g[i+1][j][1]*(p-i)*k,g[i][j-k][1]+=g[i+1][j][1];
                        }
                        else{
                            f[i][j-k][0]+=f[i+1][j][0]+g[i+1][j][0]*(p-i)*k,g[i][j-k][0]+=g[i+1][j][0];
                        }
                    }
                }
            }
        }
            for(int j=0;j<=up;j++){
                if((fix-x<=j)&&(j<x+fix)){
                    ret+=f[1][j][0]+f[1][j][1];
                }
            }
        }
    }
    return ret;
}
int main(){
    scanf("%lld%lld",&L,&R);
    scanf("%d",&m);
    L--;
    cnt=0;
    while(L){
        a[++cnt]=L%m;
        L/=m;
    }
    if(cnt==0){
        ansl=0;
    }
    else{
        ansl=wrk();
    }

    cnt=0;
    while(R){
        a[++cnt]=R%m;
        R/=m;
    }
    ansr=wrk();
    printf("%lld",ansr-ansl);
}

法二:大众法。

直接钦定1号位置是最优位置,计算出来所有的总和ans

调整。

枚举位置p从2~cnt,表示要计算从p-1移动到p,会有多少个数的代价减少多少。

代价就是,sum(1,p-1)-sum(p,cnt)

设f[i][a-b][0/1]表示,第i位,这个sum的差值,有没有限制情况下,多少个数符合这个情况。

循环完一个p之后,

把a-b<0的f,ans-=(a-b)*f[i][a-b][0/1]

a-b>=0的不管。

这样进行cnt次,一定可以把所有的数移动到最优解的位置。

网上题解很多,代码就不贴了。(我也没写)

原文地址:https://www.cnblogs.com/Miracevin/p/9526948.html

时间: 2024-11-05 22:56:02

[SCOI2014]方伯伯的商场之旅的相关文章

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

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

「SCOI2014」方伯伯的商场之旅

「SCOI2014」方伯伯的商场之旅 题目描述 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 \(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]中的数,然

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

这道题的数位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]方伯伯的玉米田

3594: [Scoi2014]方伯伯的玉米田Time Limit: 60 Sec Memory Limit: 128 MBSubmit: 1437 Solved: 647[Submit][Status][Discuss]Description方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐.方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列.方伯伯可以选择一个区间,把

bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化

3594: [Scoi2014]方伯伯的玉米田 Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 314  Solved: 132[Submit][Status] Description 方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐.方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列.方伯伯可以选择一个区间,把这个区间的