zoukankan      html  css  js  c++  java
  • [BZOJ3598] [Scoi2014]方伯伯的商场之旅

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

    Output

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

    Sample Input

    3 8 3

    Sample Output

    5

    HINT

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

    试题分析

    首先由于每个数互相独立,所以对于每个数考虑最优方案。
    那么将每个石子看成一个个体,权值为其所在堆的位置,那么显然是移动到(frac{x}{2})的位置最优。
    所以说权值是自然排好序的,那么我们只需要顺序考虑。
    总体考虑不好考虑,那么我们考虑石子个数一样的数,那么这些数的中位数是一样的,所以枚举石子个数可以直接得到中位数。
    我们就可以设(f_{i,j,k})表示前i位,总和为j,是否顶住上届的代价。
    (g_{i,j,k})表示方案数。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
     
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL MAXN = 100010;
    const LL INF = 2147483600;
     
    LL f[67][301][3],g[67][301][3];
    LL L,R,K,cnt=0; LL str[MAXN+1];
     
    inline LL init(LL x){
        cnt=0; while(x){str[++cnt]=x%K;x/=K;} LL res=0;
        for(LL s=1;s<cnt*K;s++){
            LL mid=(s+1)>>1;
            for(LL i=cnt+1;i>=0;i--)
                for(LL j=0;j<=s;j++)
                    g[i][j][0]=g[i][j][1]=f[i][j][0]=f[i][j][1]=0;
            g[cnt+1][0][1]=1;
            for(LL i=cnt+1;i>1;i--){
                for(LL j=0;j<=s;j++){
                    if(g[i][j][0]){
                        for(LL l=0;l<K;l++){
                            if(l+j>s) break;
                            g[i-1][l+j][0]+=g[i][j][0];
                            if(j>=mid) f[i-1][j+l][0]+=f[i][j][0]+g[i][j][0]*(s-j);
                            else if(j+l<mid) f[i-1][j+l][0]+=f[i][j][0]+g[i][j][0]*(j+l);
                            else f[i-1][j+l][0]+=f[i][j][0];
                        }
                    }
                    if(g[i][j][1]){
                        for(LL l=0;l<=str[i-1];l++){
                            if(l+j>s) break; LL x=(l==str[i-1]);
                            g[i-1][l+j][x]+=g[i][j][1];
                            if(j>=mid) f[i-1][j+l][x]+=f[i][j][1]+g[i][j][1]*(s-j);
                            else if(j+l<mid) f[i-1][j+l][x]+=f[i][j][1]+g[i][j][1]*(j+l);
                            else f[i-1][j+l][x]+=f[i][j][1];
                        }
                    }
                }
            }
            res+=max(f[1][s][0],0LL)+max(f[1][s][1],0LL);
        } return res;
    }
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        L=read(),R=read(),K=read(); LL ans=0;
        ans+=init(R);
        ans-=init(L-1);
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    [Panzura] identify user operations(copy, open, read ... ) in audit log
    Spark 学习
    Zeppelin 学习
    Delta Lake 学习
    传染病模型 SI
    xcodebuild和xcrun实现自动打包iOS应用程序
    控制UIlabel 垂直方向对齐方式的 方法
    ALAssetsLibrary
    CATransform3D
    AVFoundation的使用
  • 原文地址:https://www.cnblogs.com/wxjor/p/9522070.html
Copyright © 2011-2022 走看看