【BZOJ3598】【SCOI2014】方伯伯的商场之旅(数位dp)

传送门

似乎做出来之后很简单了

显然对于每一个数都是在带权中点最优
假设先把所有数都移到最后一位
再枚举有多少能往左移更优

考虑显然在找中点的时候能往左移的条件是当前位置前缀大于后缀
而前后缀之差的范围是很小的,可以直接作为状态维护

统计出所有更优的状态减一下就是了

具体看代码吧
我tm在口胡什么啊(逃)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res;
}
const int N=70,M=4006;
int l,r,k,dig[70],tot,n,f[N][M];
int dfs1(int pos,int val,int lim){
	if(!pos)return val;
	if(!lim&&f[pos][val]!=-1)return f[pos][val];
	int mx=lim?dig[pos]:k-1,res=0;
	for(int i=0;i<=mx;i++){
		res+=dfs1(pos-1,val+i*(pos-1),lim&(i==dig[pos]));
	}
	if(!lim)f[pos][val]=res;return res;
}
int dfs2(int pos,int val,int to,int lim){
	if(val<0)return 0;
	if(!pos)return val;
	if(!lim&&f[pos][val]!=-1)return f[pos][val];
	int mx=lim?dig[pos]:k-1,res=0;
	for(int i=0;i<=mx;i++){
		if(pos>=to)res+=dfs2(pos-1,val+i,to,lim&(i==dig[pos]));
		else res+=dfs2(pos-1,val-i,to,lim&(i==dig[pos]));
	}
	if(!lim)f[pos][val]=res;return res;
}
inline int solve(int x){
	tot=0;
	while(x){
		dig[++tot]=x%k;
		x/=k;
	}
	memset(f,-1,sizeof(f));
	int res=dfs1(tot,0,1);
	for(int i=2;i<=tot;i++){
		memset(f,-1,sizeof(f));
		res-=dfs2(tot,0,i,1);
	}
	return res;
}
signed main(){
	l=read(),r=read(),k=read();
	cout<<(solve(r)-solve(l-1))<<'
';
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145589.html