[SCOI2014]方伯伯的商场之旅
题目
另类的数位动规
做法
考虑移动一个数,将原答案点\(i\)右移一位,答案增量为左边和-右边和
利用这个贪心对于每个数都能确定一个位置,爆搜枚举每个数的答案位置
My complete code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL l,r,k,tot;
LL a[120],f[120][5000+10]={0};
LL Dfs1(LL now,LL sum,LL top){
if(!now) return sum;
if(!top&&f[now][sum]) return f[now][sum];
LL ret=0;
LL Up=top?a[now]:k-1;
for(LL i=0;i<=Up;i++) ret+=Dfs1(now-1,sum+(now-1)*i,top&&i==Up);
if(!top) f[now][sum]=ret;
return ret;
}
LL Dfs2(LL now,LL sum,LL pos,LL top){
if(sum<0) return 0;
if(!now) return sum;
if(!top&&f[now][sum]) return f[now][sum];
LL ret=0;
LL Up=top?a[now]:k-1;
for(LL i=0;i<=Up;i++){
if(now>=pos) ret+=Dfs2(now-1,sum+i,pos,top&&i==Up);
if(now<pos) ret+=Dfs2(now-1,sum-i,pos,top&&i==Up);
}
if(!top) f[now][sum]=ret;
return ret;
}
inline LL Solve(LL x){
LL tot(0);
while(x)
a[++tot]=x%k, x/=k;
LL ret=0;
memset(f,0,sizeof(f));
ret+=Dfs1(tot,0,1);
for(LL i=2;i<=tot;i++){
memset(f,0,sizeof(f));
ret-=Dfs2(tot,0,i,1);
}
return ret;
}
int main(){
cin>>l>>r>>k;
cout<<Solve(r)-Solve(l-1);
return 0;
}