1561D1 - Up the Strip (simplified version)

本文解析了一道关于数字变化路径问题的Codeforces竞赛题目,通过动态规划结合特殊除法规则,展示了如何用C++实现求解从n到1的不同操作方法数量。关键在于理解减法和除法操作的递推关系,并利用区间dp优化计算。
摘要由CSDN通过智能技术生成

链接:

https://codeforces.com/problemset/problem/1561/D1

题意:

一开始为n,把n变成1,可以做两种操作(无数次)

对于位置x的数字:

1、减【1,x-1】任意一个数

2、除与【2,x】任意一个数(向下取整)

求有多少种变法

输入

3 998244353

输出量

5

输入

5 998244353

输出量

25

输入

42 998244353

输出量

793019428

解:

这一波属于是1900大佬提点了,一开始就想到了DP,但是除法这部分完全不会写

因为x的数字可以减【1,x-1】任意一个数字,所以x可以变成【1,x-1】任何一个数字

所以减法反面,dp[i]首先要继承i+1到n所有dp的和,因为前面任意一种都可以通过减法达成i;

然后是除法部分,只能说是妙哇

正常要把dp[i]放入每一个i/2,i/3,…,i/i;

但是!!!

由于向下取整,所以导致i除某些数字结果是同一个数,比如3/2=1,3/3=1;

所以在一个区间的dp[i/(l~r)]其实全部属于dp[i/p]!

上面的例子表示l=2,r=3的区间都属于dp[1],所以r-l+1*dp[3]加入dp[1]即可

而选取右端点的方法就是i/(i/l)!!!,l为左端点

实际代码:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#define csh(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long int ll;
const int N=4E6+10; 
ll mod;
ll sum=0;
ll ans;
ll dp[N];
int main()
{
	ll n,m;
	cin>>n>>m;
	dp[n]=1;
	mod=m;ans=0;
	for(ll i=n;i>=2;i--)
	{
		dp[i]=(dp[i]+sum)%mod;//继承部分 减法部分 
		for(int l=2,r=i/(i/l);l<=i;l=r+1)
		{
			r=i/(i/l);//右端点确定 
			dp[i/l]=(dp[i/l]+(r-l+1)*dp[i])%mod;//继承部分 除法部分 
		}
		sum=(sum+dp[i])%mod;//把i和前面的方法数和记录,留给i-1; 
	}
	cout<<(dp[1]+sum+mod)%mod<<endl;
	return 0;
}

限制:

time limit per test

6 seconds

memory limit per test

128 megabytes

input

standard input

output

standard output

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值