P3286 [SCOI2014] 方伯伯的商场之旅

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

1.将集结点放在1号位
2 若移动 产生的data==pre(n)-suf(n+1) 正数不动 负数 动
3 数位DP一号 再DP后面的位数

*/
/*
3 8 3
5

*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int num[60],len;
ll L,R,K,f[60][2000];

ll dfs1(int pos,ll sum,int lim)
{
    if(pos==0) return sum;
    if(lim==0&&f[pos][sum]!=-1) return f[pos][sum];
    int end=lim? num[pos]:K-1;
    ll ans=0;
    for(int i=0;i<=end;i++){
        ans+=dfs1(pos-1,sum+(pos-1)*i,lim&&i==end);
    }
    if(lim==0) f[pos][sum]=ans;
    return ans;
}
ll dfs2(int pos,ll sum,int to,int lim)
{
    if(pos==0) return min(sum,0LL);
    if(lim==0&&f[pos][sum]!=-1) return f[pos][sum];
    int end=lim? num[pos]:K-1;
    ll ans=0;
    for(int i=0;i<=end;i++){
        ans+=dfs2(pos-1,sum+(pos>=to? -i:i),to,lim&&i==end);
    }
    if(lim==0) f[pos][sum]=ans;
    return ans;
}

ll solve(ll x)
{
    len=0;
    while(x){
        num[++len]=x%K;
        x/=K;
    }
    memset(f,-1,sizeof(f));
    ll ans=dfs1(len,0,1);
    for(int i=2;i<=len;i++){
        memset(f,-1,sizeof(f));
        ans+=dfs2(len,0,i,1);
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
       cin>>L>>R>>K;
       cout<<solve(R)-solve(L-1)<<'\n';
       
    return 0;
}

 

posted @ 2024-02-08 17:00  JMXZ  阅读(17)  评论(0)    收藏  举报