CF479E Riding in a Lift gxy001

考虑 dp\text{dp}

状态转移方程


我们定义 fi,jf_{i,j} 为走到第 ii 层,共走了 jj 次的方案数,容易得到转移方程:

fi,j=k=downupfk,j1 [ki]f_{i,j}=\sum\limits_{k=down}^{up} f_{k,j-1}\ [k\ne i]

其中 downdown 为能走到 ii 层的下界,upup 为上界。

时间复杂度 O(n2k)O(n^2k),显然无法 A\text{A} 掉此题。这时,有经验的 OIer\text{OIer} 就会发现,这是可以用前缀和优化的。我们设 si,j=k=1ifk,js_{i,j}=\sum\limits_{k=1}^if_{k,j},得到新的转移方程:

fi,j=sup,j1sdown1,j1fi,j1f_{i,j}=s_{up,j-1}-s_{down-1,j-1}-f_{i,j-1}

时间复杂度 O(nk)O(nk),可以 AC\text{AC}

一些细节


显然,由于 xy<xb\mid x-y\mid <\mid x-b\mid 的限制,你只能在 bb 的一侧运动,那么,我们可以将 bb 层当做 00 层。

if(a>b) n-=b,a-=b;
else n=b-1,a=b-a;

这样,我们就可以快速的求出 upupdowndown 了,up=nup=ndown=i2+1down=\lfloor\frac i 2\rfloor+1


初始化:fa,0=1f_{a,0}=1


我们注意到,jj 次的方案数只依赖于 j1j-1 次,所以我们可以采用滚动数组对空间进行优化。

代码


#include<cstdio> //for printf,scanf
#include<algorithm> //for min
int const mod=1000000007;
long long n,k,a,b,f[5010],s[5010];
int main(){
	scanf("%lld%lld%lld%lld",&n,&a,&b,&k);
	if(a>b) n-=b,a-=b;
	else n=b-1,a=b-a;
	f[a]=1;
	for(int i=a;i<=n;i++)s[i]=1;
	for(int i=1;i<=k;i++){
		for(int j=1;j<=n;j++) f[j]=(s[n]-s[j>>1]-f[j]+mod+mod)%mod;
		for(int j=1;j<=n;j++) s[j]=(s[j-1]+f[j])%mod;
	}
	printf("%lld",s[n]);
	return 0;
}

来发评论吧~
Powered By Valine
v1.4.14
欢迎来到本站!