题目如下:
思路 or 题解:
我们可以设: 第一个数为
x
x
x
d = {a, -b}
那后续的数为:
x
+
d
1
x + d_1
x+d1 ,
x
+
d
1
+
d
)
2
x + d_1 + d_)2
x+d1+d)2 … …
x
+
d
1
+
d
2
+
.
.
.
.
.
.
+
d
n
−
1
x + d_1 + d_2 + ... ... + d_{n - 1}
x+d1+d2+......+dn−1
根据题意和上面的式子
我们合并一下同类项:
n
∗
x
+
(
n
−
1
)
∗
d
1
+
(
n
−
2
)
∗
d
2
+
.
.
.
.
.
.
+
d
n
−
1
=
s
n * x + (n - 1) * d_1 + (n - 2) * d_2 + ... ... + d_{n-1} = s
n∗x+(n−1)∗d1+(n−2)∗d2+......+dn−1=s
我们可以解出
x
x
x
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
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
这就将题转变成组合问题了,可以用背包的思想去解决!
状态表示:
f
[
i
]
[
j
]
f[i][j]
f[i][j] 选了
i
i
i 个
d
d
d, 余数为
j
j
j 的方案数。
状态计算:
- 选 a: f [ i ] [ j ] = f [ i − 1 ] [ j − a ∗ i ] f[i][j] = f[i-1][j - a * i] f[i][j]=f[i−1][j−a∗i]
- 选 -b:
d
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
+
b
∗
i
]
d[i][j] = f[i - 1][j + b*i]
d[i][j]=f[i−1][j+b∗i]
特别注意: C++数组下标不能取负数,所以我们需要写一个函数,来确保计算出来的数为非负数。
auto getmod = [&](int x)
{
return (x % n + n) % n;
};
时间复杂度: 0 ( n 2 ) 0(n^2) 0(n2)
AC 代码:
const int mod = 100000007;
const int inf = 2147483647;
const int N = 100009;
int n, s, a, b;
int f[1009][1009];
void solve()
{
cin >> n >> s >> a >> b;
f[0][0] = 1;
auto getmod = [&](int x)
{
return (x % n + n) % n;
};
for (int i = 1; i < n; i++)
for (int j = 0; j < n; j++)
f[i][j] = (f[i - 1][getmod(j - a * i)] + f[i - 1][getmod(j + b * i)]) % mod;
cout << f[n - 1][getmod(s)] << '\n';
}
int main()
{
buff;
solve();
}