题目描述
原题链接:1214.波动数列
解题思路
1.分析时间复杂度
在题目中:1 ≤ n ≤ 1000 \le n \le 1000 ≤n≤1000, n 2 = 1 0 6 < 1 0 8 n^2=10^6 \lt 10^8 n2=106<108,因此本题的时间复杂度差不多 o ( n 2 ) o(n^2) o(n2)。
2.数学推导
假设数列的第一个数为
x
x
x,第
i
i
i次操作的数为
d
i
d_i
di,
d
i
=
+
a
d_i=+a
di=+a或
−
b
-b
−b。
那么一个长度为
n
n
n的数列就是
x
,
x
+
d
1
,
x
+
d
1
+
d
2
,
.
.
.
,
x
+
d
1
+
d
2
+
.
.
.
+
d
n
−
1
x,x+d_1,x+d_1+d_2,...,x+d_1+d_2+...+d_{n-1}
x,x+d1,x+d1+d2,...,x+d1+d2+...+dn−1。
这一串数列的和就是
n
x
+
(
n
−
1
)
d
1
+
(
n
−
2
)
d
2
+
.
.
.
+
d
n
−
1
=
s
nx+(n-1)d_1+(n-2)d_2+...+d_{n-1}=s
nx+(n−1)d1+(n−2)d2+...+dn−1=s。
进行变换后可得,
x
=
s
−
(
n
−
1
)
d
1
−
(
n
−
2
)
d
2
−
.
.
.
−
d
n
−
1
n
x=\frac{s-(n-1)d_1-(n-2)d_2-...-d_{n-1}}{n}
x=ns−(n−1)d1−(n−2)d2−...−dn−1
因为
x
x
x是整数,所以
s
−
(
n
−
1
)
d
1
−
(
n
−
2
)
d
2
−
.
.
.
−
d
n
−
1
s-(n-1)d_1-(n-2)d_2-...-d_{n-1}
s−(n−1)d1−(n−2)d2−...−dn−1一定是
n
n
n的倍数,即
s
s
s与
(
n
−
1
)
d
1
+
(
n
−
2
)
d
2
+
.
.
.
+
d
n
−
1
(n-1)d_1+(n-2)d_2+...+d_{n-1}
(n−1)d1+(n−2)d2+...+dn−1模
n
n
n同余。这其实是一个组合问题,在
n
−
1
n-1
n−1个操作下,如何组合使得数列之和与
s
s
s同余。
3.闫氏dp分析
假设f[i][j]
表示在考虑第
i
i
i次操作下,即第
i
i
i次操作
+
a
+a
+a或
−
b
-b
−b,前
i
+
1
i+1
i+1个数模
n
n
n结果为
j
j
j的方案数。
假如第
i
i
i次操作是
+
a
+a
+a,那么前
i
+
1
i+1
i+1个数字的和是
x
+
(
n
−
1
)
d
1
+
(
n
−
2
)
d
2
+
.
.
.
+
(
n
−
(
i
−
1
)
)
d
i
−
1
+
(
n
−
i
)
a
≡
j
(
m
o
d
n
)
x+(n-1)d_1+(n-2)d_2+...+(n-(i-1))d_{i-1}+(n-i)a \equiv j(mod \ n)
x+(n−1)d1+(n−2)d2+...+(n−(i−1))di−1+(n−i)a≡j(mod n)。
那么,
x
+
(
n
−
1
)
d
1
+
(
n
−
2
)
d
2
+
.
.
+
(
n
−
(
i
−
1
)
d
i
−
1
≡
j
−
(
n
−
i
)
a
(
m
o
d
n
)
x+(n-1)d_1+(n-2)d_2+..+(n-(i-1)d_{i-1} \equiv j-(n-i)a \ (mod \ n)
x+(n−1)d1+(n−2)d2+..+(n−(i−1)di−1≡j−(n−i)a (mod n)。上述左端的式子刚好为考虑
i
−
1
i-1
i−1次操作之后数列的和。
通过以上的分析我们可以知道,当第
i
i
i次操作为
+
a
+a
+a时,方案数为f[i-1][j-(n-1)*a]
。同理,当第
i
i
i次操作为
−
b
-b
−b时,方案数为f[i-1][j+(n-1)*b]
。
即f[i][j] = f[i-1][j-(n-1)*a] + f[i-1][j+(n-1)*b]
。
4.一些注意点
(1)由于
j
−
(
n
−
1
)
∗
a
j-(n-1)*a
j−(n−1)∗a和
s
s
s都有可能是负数,而数组下标只能大于等于0,因此在取模的时候要注意是结果必须大于等于0。
(2)关于初始化的问题,当
i
=
0
i=0
i=0时,满足题意的方案只有一种,就是
x
=
s
x=s
x=s,因此f[0][0] = 1
。
c++代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
const int P = 1e8+7;
int n,s,a,b,f[N][N];
int get_mod(int a, int b)
{
return (a % b + b) % b;
}
int main()
{
cin >> n >> s >> a >> b;
f[0][0] = 1;
for(int i = 1; i < n; i++)
{
for(int j = 0; j < n; j++)
{
f[i][j] = (f[i-1][get_mod(j-(n-i)*a, n)] + f[i-1][get_mod(j+(n-i)*b, n)]) % P;
}
}
cout << f[n-1][get_mod(s,n)];
}