您的位置:首页 > 其它

bzoj3598 [Scoi2014]方伯伯的商场之旅

2018-03-11 16:43 429 查看
数位dp,我们肯定枚举集合的位置,但是如果每次都重新dp的话会很麻烦,所以我们可以先钦定在最低位集合,dp出代价,然后再一步步找到正确的集合点,每次更改的代价也dp算就好了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define int long long
using namespace std;
int L,R,K;
int a[66];
int f[66][1500];
int dfs(int pos,int sum,int lim){
if(!pos)return sum;
if(!lim&&f[pos][sum]!=-1)return f[pos][sum];
int up=lim?a[pos]:K-1;
int ans=0;
for(int i=0;i<=up;i++)
ans+=dfs(pos-1,sum+(pos-1)*i,lim&&(i==up));
if(!lim)f[pos][sum]=ans;
return ans;
}
int dfs(int pos,int zd,int sum,int lim){
if(sum<0)return 0;
if(!pos)return sum;
if(!lim&&f[pos][sum]!=-1)return f[pos][sum];
int up=lim?a[pos]:K-1;
int ans=0;
for(int i=0;i<=up;i++){
if(pos>=zd)ans+=dfs(pos-1,zd,sum+i,lim&&(i==up));
else ans+=dfs(pos-1,zd,sum-i,lim&&(i==up));
}
if(!lim)f[pos][sum]=ans;
return ans;
}
int work(int x){
int pos=0;
while(x){
a[++pos]=x%K;
x/=K;
}
memset(f,-1,sizeof f);
int ans=dfs(pos,0,1);
for(int i=2;i<=pos;i++){
memset(f,-1,sizeof f);
ans-=dfs(pos,i,0,1);
}
return ans;
}
signed main(){
scanf("%lld%lld%lld",&L,&R,&K);
printf("%lld\n",work(R)-work(L-1));
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: