P6189 [NOI Online #1 入门组] 跑步(分拆数)

简要题意

给你一个整数 n,你需要求 i=1nxi=nxixi+1 的非负整数解数量对给定模数 p 取模后的结果。

n105

分析

考虑一个显然的 DP:设 fi,j 表示考虑 1i 这些数,总和为 j 的方案数。转移是完全背包型转移:fi,j=fi1,j+fi,ji。时间复杂度 O(n2),飞了。

考虑优化。

注意到当取的数较大的时候,取的数不会太多。

考虑根号分治,设阈值 B=n,那么 >B 的数选的数的个数 B。设 gi,j 表示选了 i 个数,选的数的和是 j 的方案数。我们在选数的时候,先固定选了 iB,然后每次考虑若要选更大的数,我们就给当前的数全局加 1。那么写成转移方程就是 gi,j=gi1,jB+gi,ji。结合暴力 DP 时间复杂度 O(nn)

int n,mod;
int f[maxm][maxn],g[maxm][maxn];
int F[maxn],G[maxn];
void add(int &x,int y){x+=y,x=x>=mod?x-mod:x;} 
void solve_the_problem(){
	rd(n),rd(mod);
	f[0][0]=1;
	rep(i,1,B-1)rep(j,0,n){
		add(f[i][j],f[i-1][j]);
		if(j>=i)add(f[i][j],f[i][j-i]);
	}
	rep(i,0,n)F[i]=f[B-1][i];
	g[0][0]=G[0]=1;
	rep(i,1,B)rep(j,0,n){
		if(j>=B)add(g[i][j],g[i-1][j-B]);
		if(j>=i)add(g[i][j],g[i][j-i]);
		add(G[j],g[i][j]);
	}
	int ans=0;
	rep(i,0,n)ans=(ans+1ll*F[i]*G[n-i]%mod)%mod;
	write(ans);
}

作者:dcytrl

出处:https://www.cnblogs.com/dcytrl/p/18489868

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   dcytrl  阅读(21)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示