题目 题意:对于一个数x,有两种操作,
- 减k,数x跳到
x
?
k
,
k
∈
[
1
,
x
?
1
]
x-k,k\in [1,x-1]
x?k,k∈[1,x?1]
- 除k, 数x跳到
?
x
/
k
?
,
k
∈
[
2
,
x
]
\lfloor x/k \rfloor, k \in[2,x]
?x/k?,k∈[2,x]
先给定n和m,求从n跳到1有多少种跳法,答案对m取模。
思路:按着官方题解的D1思路来,减法的部分我们可以直接用前缀和维护。对于除法的部分,拆解成两个部分。 对于
k
∈
[
2
,
s
q
r
t
(
n
)
]
k\in[2,sqrt(n)]
k∈[2,sqrt(n)],直接求解加起来 对于
k
∈
[
s
q
r
t
(
n
)
,
n
]
k\in[sqrt(n),n]
k∈[sqrt(n),n],求解每个k对应的
?
x
/
k
?
\lfloor x/k \rfloor
?x/k?落在
[
2
,
s
q
r
t
(
n
)
]
[2,sqrt(n)]
[2,sqrt(n)]的哪个区间(因为k>=sqrt(n),必有
?
x
/
k
?
\lfloor x/k \rfloor
?x/k? <= sqrt(n))。所以这部分的数据,我们可以反过来枚举
?
x
/
k
?
\lfloor x/k \rfloor
?x/k?落在
[
2
,
s
q
r
t
(
n
)
]
[2,sqrt(n)]
[2,sqrt(n)]的数,对应的k的范围。 注意计算的时候对于边界sqrt(n)计算的要注意,不重不漏。 代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200010;
int n, mod;
int f[maxn];
int sub_mod(int a, int b) {
int res = a - b;
if (res < 0) res += mod;
return res;
}
int add_mod(int a, int b) {
int res = a + b;
if (res >= mod) res -= mod;
return res;
}
int mul(int a, int b) {
return 1LL * a * b % mod;
}
int count(int n, int c) {
int a = n / (c + 1) + 1;
int b = n / c;
return b - a + 1;
}
int main() {
scanf("%d%d", &n, &mod);
f[1] = 1;
int pre = f[1];
for (int i = 2; i <= n; ++i) {
f[i] = pre;
int m = sqrt(1.0 * i);
for (int j = 2; j < m; ++j) {
f[i] = add_mod(f[i], f[i / j]);
}
if (m != i / m && m >= 2) {
f[i] = add_mod(f[i], f[i/m]);
}
for (int j = 1; j <= m; ++j) {
f[i] = add_mod(f[i], mul(f[j], count(i, j)));
}
pre = add_mod(pre, f[i]);
}
printf("%d\n", f[n]);
}
参考这篇博客,写法更简洁,日常觉得大佬的思路比题解的还好。数论分块
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
vector<int> v[maxn];
vector<pair<int,int>> s;
ll dp[maxn];
int main()
{
ll n,m;
cin>>n>>m;
dp[1]=1;
ll sum=1;
for(int i=2;i<=n;i++)
{
dp[i]+=sum;
for(int l=2,r=0;l<=i;l=r+1)
{
r=i/(i/l);
dp[i]+=1ll*dp[i/l]*(r-l+1);
dp[i]%=m;
}
sum+=dp[i];
sum%=m;
}
cout<<dp[n];
return 0;
}
对于D2,用了差分的思想。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=6e6+6;
ll dp[maxn];
int main()
{
ll n,m;
cin>>n>>m;
dp[1]=1;
dp[2]=m-1;
for(int i=1;i<=n;i++)
{
dp[i]+=dp[i-1];
dp[i]%=m;
dp[i+1]+=dp[i];
dp[i+1]%=m;
for(ll j=2;j*i<=n;j++)
{
dp[j*i]=dp[j*i]+dp[i];
dp[j*i]%=m;
if(j*i+j<=n)
{
dp[j*i+j]-=dp[i];
dp[j*i+j]%=m;
dp[j*i+j]+=m;
dp[j*i+j]%=m;
}
}
}
cout<<dp[n];
return 0;
}
|