ABC178 D - Redistribution
求将 S ( 1 ≤ N ≤ 2000 ) S(1 \le N \le 2000) S(1≤N≤2000)拆分为一个序列,且序列中所有值均 ≥ 3 \ge 3 ≥3的方案数。 ( m o d 1 e 9 + 7 ) (~mod~1e9+7) ( mod 1e9+7)
Solution
计数DP?
状态:设
f
[
i
]
f[i]
f[i]表示第
i
i
i个数的方案数。
转移:
f
[
i
]
=
∑
j
=
0
i
−
3
f
[
j
]
f[i]=\sum _{j=0} ^{i-3} f[j]
f[i]=∑j=0i−3f[j],表示结尾数为
i
−
j
i-j
i−j的方案数。
初始化:
f
[
3
]
=
1
f[3]=1
f[3]=1
这样我们就得到了一个
O
(
N
2
)
O(N^2)
O(N2)的DP。
Extra
这道题可以
O
(
N
)
O(N)
O(N)解决。
转移改为:
f
[
i
]
=
f
[
i
−
1
]
+
f
[
i
−
3
]
f[i]=f[i-1]+f[i-3]
f[i]=f[i−1]+f[i−3]即可,
f
[
i
−
1
]
=
∑
j
=
0
i
−
4
f
[
j
]
f[i-1]=\sum _{j=0} ^{i-4} f[j]
f[i−1]=∑j=0i−4f[j],这道题的DP本质是一个前缀和,自然可以优化为线性。
Code
#include <bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll N = 3e3 + 5;
ll f[N],n;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
f[3]=1;
for(int i=4;i<=n;i++) f[i]=(f[i-1]+f[i-3])%mod;
cout<<f[n];
return 0;
}