bzoj 3598: [Scoi2014]方伯伯的商场之旅【数位dp】

参考了这个http://www.cnblogs.com/Artanis/p/3751644.html,好像比一般方法好写
大概思想就是先计算出把所有石子都合并到1位置的代价,这样显然有一些是不优的,然后再分别计算把合并到1的石子合并到p,能优化多少
这个计算就是枚举2到tot位,对于每一位计算挪到这位能被优化的数最多能被优化多少,因为合并点右移的代价是sum[w]-(sum[n]-sum[w]),所以只要这个为负数就退出即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1005;
long long l,r,k,f[N][2],sm[N][2],g[N][N],a[N],tot;
long long dp(int w,int lm)
{
	if(w==0)
	{
		sm[w][lm]=1;
		return 0;
	}
	if(f[w][lm])
		return f[w][lm];
	long long r=0,s=0;
	for(int i=0;i<=(lm?a[w]:k-1);i++)
	{
		r+=dp(w-1,lm&&(i==a[w]))+i*(w-1)*sm[w-1][lm&&(i==a[w])];
		s+=sm[w-1][lm&&(i==a[w])];
	}
	sm[w][lm]=s;
	return f[w][lm]=r;
}
long long wk(long long x)
{
	memset(f,0,sizeof(f));
	tot=0;
	while(x)
		a[++tot]=x%k,x/=k;
	return dp(tot,1);
}
long long dfs(int w,int lm,int p,int s)
{
	if(w==0)
		return s;
	if(!lm&&g[w][s])
		return g[w][s];
	long long r=0;
	for(int i=0;i<=(lm?a[w]:k-1);i++)
	{
		long long nw=(w>=p?1:-1)*i+s;
		if(nw<0)
			break;
		r+=dfs(w-1,lm&&i==a[w],p,nw);
	}
	if(lm)
		return r;
	return g[w][s]=r;
}
long long clc(long long x)
{
	tot=0;
	while(x)
		a[++tot]=x%k,x/=k;
	long long r=0;
	for(int i=2;i<=tot;i++)
	{
		memset(g,0,sizeof(g));
		r+=dfs(tot,1,i,0);
	}
	return r;
}
int main()
{
	scanf("%lld%lld%lld",&l,&r,&k);
	printf("%lld
",wk(r)-wk(l-1)-(clc(r)-clc(l-1)));
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/9617139.html