cf1561D 整除分块,DP。

2 篇文章 0 订阅
题目链接

https://codeforces.com/contest/1561/problem/D2

题意

n阶台阶下楼梯,可以一次走多步,可以一次从当前格子x走到x/z(下取整)格子。z可在1到x-1选择。问走到1的方案数。

思路

考虑dp
第一种操作很容易处理。dp[i]可以直接由sum[i-1]转移过来。
第二种操作其实也简单,我们就枚举z,然后从x/z转移不得了。
但是这样的复杂度是n平方的,这时要用到一些优化。
考虑整除分块,一个数的约数显然只有根号级别,也就是说我们枚举z的时候有很多是重复的,那么我们不如枚举x/z的结果,套一个整除分块板子,复杂度是n根号n,可以通过。

再考虑D2。
我们考虑倒推,将dp数组意义改为走到i位置的方案数,那么初态dp[n]=1,答案是dp[1].一个状态dp[i]的转移就是由i+1到n的后缀和作为第一种操作,第二种操作,则是枚举所有j,让j是i的倍数,之后计算这个倍数的贡献。比如当前是x,那么我们有2x,2x+1两个位置计算的是dp[2x]的转移,3x,3x+1,3x+2三个位置计算的是dp[3x]的转移,以此类推。容易发现复杂度是调和级数。

代码
D1   数组叫bit是因为刚开始脑子不清楚,套了个树状数组
void solve(){
		cin>>n>>mod;
		bit[1]=1;
		int sum=1;
		for(int i=2;i<=n;i++){
			int t=sum;
			for(int l=2,r;l<=i;l=r+1){
				r=i/(i/l);
				t=(t+bit[i/l]*((r-l+1ll)%mod))%mod;
			}
			bit[i]=t;
			sum=(sum+t)%mod;
		}
		cout<<bit[n]<<endl;
	}
	void solve(){
		cin>>n>>mod;
		bit[n]=1;
		sum[n]=1;
		for(int i=n-1;i;i--){
			bit[i]=sum[i+1]%mod;
			for(int j=2;j*i<=n;j++){
				int l=i*j,r=min(n,i*j+j-1);
				bit[i]=(bit[i]+sum[l]-sum[r+1]+mod)%mod;
			}
			sum[i]=(bit[i]+sum[i+1])%mod;
		}
		cout<<bit[1]<<endl;
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值