• BZOJ.3598.[SCOI2014]方伯伯的商场之旅(贪心 数位DP)


    题目链接

    先考虑,对于确定的一个数,怎样移动代价最少(或者移到哪个位置最优)?
    假设我们都移到下标(1)位置(设集合点为(1)),那么移动到下标(2)(1)相比代价差为:(下标<1的石子数和-下标>1的石子数和)
    如果它为负,那么把移到(1)的代价加上它,令集合点变为(2)...
    这样一直改变集合点,直到 (下标<p的石子数和 geq 下标>p的石子数和)。那么移到(p)就是最优的。

    这样感觉很对。怎么证明?
    我们发现式子左边其实就是前缀和,右边是后缀和。因为石子数非负,所以随着(p)移动,前缀和是递增的,后缀和递减。
    即如果出现 (前缀和 geq 后缀和) 的情况,前缀和就永远大于等于后缀和了。

    那么我们对([l,r])的所有数都进行这个贪心。
    首先我们要算出所有数集合到1的代价和。这个可以用数位DP算出(递推数的个数,用个数求和)。

    然后枚举(p=2sim n)位,我们可以求 以(p)为分界,前缀数位和 小于 后缀数位和 且 在([0,r]) 的数的个数。其中每个数会减少的代价就是(前缀和-后缀和)
    因为数位和最多差不多是230,可以直接枚举这两个状态。同样数位DP。
    (f[i][j][k][0/1])表示当前到第(i)位,总数位和为(j)(p)位之前的数位和为(k),是否到上界,的数的个数。

    另外还可以直接减掉(k)那一维。。
    记忆化就好写的多了(还快)。

    //49592kb	404ms
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long LL;
    const int N=52,M=245;
    
    int A[N];
    LL g[N][2],sum[N][2],f[N][M][M][2];
    
    LL Calc(LL x,int base)
    {
    	int n=0;
    	for(; x; x/=base) A[++n]=x%base;
    	std::reverse(A+1,A+1+n);//
    
    	memset(g,0,sizeof g), memset(sum,0,sizeof sum);
    	g[0][1]=1;
    	for(int i=0; i<n; ++i)//好像还是从0方便。。
    	{
    		LL v=g[i][1]; int ai=A[i+1];
    		g[i+1][1]+=v, sum[i+1][1]=sum[i][1]+v*i*ai;
    		for(int j=0; j<ai; ++j) g[i+1][0]+=v, sum[i+1][0]+=sum[i][1]+v*i*j;
    		v=g[i][0];
    		for(int j=0; j<base; ++j) g[i+1][0]+=v, sum[i+1][0]+=sum[i][0]+v*i*j;
    	}
    
    	LL ans=sum[n][0]+sum[n][1];
    	for(int p=1; p<n; ++p)
    	{
    		f[0][0][0][1]=1;
    		for(int i=0; i<n; ++i)
    		{
    			int ai=A[i+1];
    			if(i+1<=p)
    			{
    				LL v;
    				for(int j=0,lim=i*(base-1); j<=lim; ++j)
    				{
    					if(v=f[i][j][j][1])//好不直观。。
    					{
    						f[i+1][j+ai][j+ai][1]+=v;//+=
    						for(int k=0; k<ai; ++k) f[i+1][j+k][j+k][0]+=v;
    					}
    					if(v=f[i][j][j][0])
    						for(int k=0; k<base; ++k) f[i+1][j+k][j+k][0]+=v;
    				}
    			}
    			else
    			{
    				LL v;
    				for(int j=0,lim=i*(base-1); j<=lim; ++j)
    					for(int k=0,lim2=p*(base-1); k<=lim2;  ++k)
    					{
    						if(v=f[i][j][k][1])
    						{
    							f[i+1][j+ai][k][1]+=v;
    							for(int l=0; l<ai; ++l) f[i+1][j+l][k][0]+=v;
    						}
    						if(v=f[i][j][k][0])
    							for(int l=0; l<base; ++l) f[i+1][j+l][k][0]+=v;
    					}
    			}
    		}
    		for(int i=0,lim=p*(base-1); i<=lim; ++i)//pre
    			for(int j=i+1,lim2=n*(base-1); i+j<=lim2; ++j)//suf
    				ans+=(i-j)*(f[n][i+j][i][0]+f[n][i+j][i][1]);
    		for(int i=1; i<=n; ++i)
    			for(int j=0,lim=i*(base-1); j<=lim; ++j)
    				for(int k=0,lim2=p*(base-1); k<=lim2; ++k)
    					f[i][j][k][0]=0, f[i][j][k][1]=0;
    	}
    	return ans;
    }
    
    int main()
    {
    	LL L,R; int K; scanf("%lld%lld%d",&L,&R,&K);
    	printf("%lld
    ",Calc(R,K)-Calc(L-1,K));
    	return 0;
    }
    
  • 相关阅读:
    React 获取服务器API接口数据:axios、fetchJsonp
    nvm管理node版本
    windows自定义命令的创建
    目标平台、活动平台 配置,出现未能加载文件或程序集“xxx”或它的某一个依赖项报错
    Quartz.net使用总结
    vs 2010 中类文文件模板的修改
    js获取url参数的两种方法
    遍历文件夹
    简单多条件动态查询的实现
    ajax请求跨域问题
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9722666.html
Copyright © 2020-2023  润新知