题目描述
一个数字被称为好数字当他满足下列条件:
- 它有 2 × n 2 \times n 2×n 个数位, n n n 是正整数(允许有前导0);
- 构成它的每个数字都在给定的数字集合 S S S 中;
- 它前 n n n 位之和与后 n n n 位之和相等或者它奇数位之和与偶数位之和相等。例如对于 n = 2 , S = { 1 , 2 } n=2,S=\{1,2\} n=2,S={1,2},合法的好数字有 1111 , 1122 , 1212 , 1221 , 2112 , 2121 , 2211 , 2222 1111,1122,1212,1221,2112,2121,2211,2222 1111,1122,1212,1221,2112,2121,2211,2222 这样8个。
已知 n n n,求合法的好数字的个数 mod 999983 999983 999983。
输入格式
第一行一个数
n
n
n。
接下来一个长度不超过
10
10
10 的字符串,表示给定的数字集合。
输出格式
一行一个数字表示合法的好数字的个数 mod 999983 999983 999983。
样例
样例输入 #1
2
0987654321
样例输出 #1
1240
样例输入 #2
100
9765320
样例输出 #2
938457
提示
对于
20
20%
20 的数据,
n
≤
7
n \leq 7
n≤7。
对于
100
100%
100 的.据,
n
≤
1000
,
∣
S
∣
≤
10
n \leq 1000,|S| \leq 10
n≤1000,∣S∣≤10。
解题思路
前置知识:容斥原理。
令
- 构成它的每个数字都在给定的数字集合 S S S 中;
- 它前 n n n 位之和与后 n n n 位之和相等或者它奇数位之和与偶数位之和相等。例如对于 n = 2 , S = { 1 , 2 } n=2,S=\{1,2\} n=2,S={1,2},合法的好数字有 1111 , 1122 , 1212 , 1221 , 2112 , 2121 , 2211 , 2222 1111,1122,1212,1221,2112,2121,2211,2222 1111,1122,1212,1221,2112,2121,2211,2222 这样8个。
分别为条件A、条件B。
由于要求的数可以满足两个条件 A、B 中的任意一个,可以先求出满足 A条件的个数,再求出满足 B 条件的个数,最后求出同时满足A、B的个数, A + B − A ∩ B A+B-A∩B A+B−A∩B 就是答案。
-
满足 A 条件:
设 f i , j f_{i,j} fi,j 表示从集合 S S S 中取出的数,组成 i i i 位,和为 j j j 的方案数。
递推式: f i , j = ∑ f i − 1 , j − S k f_{i,j} =\sum f_{i - 1,j - S_k} fi,j=∑fi−1,j−Sk。
那么可以枚举前 n n n 位和为 x x x 的方案即所有的 f n , x f_{n,x} fn,x,由于要满足后 n n n 位与前 n n n 位和相等,那么后n位的方案数也是 f n , x f_{n,x} fn,x,两者相乘就是满足条件 A 的方案数,为 f n , x 2 f_{n,x}^2 fn,x2。 -
满足 B 条件:
显然,偶数位上的所有数长度为 n n n,奇数位上的所有数长度也是 n n n。可以把奇数序列当做一个单独的序列,偶数序列当做一个单独的序列,那么方案数就和满足条件 A 的方案数一样了,也为 f n , x 2 f_{n,x}^2 fn,x2。 -
同时满足 A 条件与 B 条件:
设该数列的奇数位序列为 X,偶数位序列为 Y。X 的前半段和与后半段和为分别为 x 1 x_1 x1、 x 2 x_2 x2,Y 的前半段和与后半段和分别为 y 1 y_1 y1、 y 2 y_2 y2。要求同时满足条件A与条件B,则 x 1 + x 2 = y 2 + y 2 x_1 + x_2= y_2 + y_2 x1+x2=y2+y2 且 x 1 + y 1 = x 2 + y 2 x_1 + y_1= x_2 + y_2 x1+y1=x2+y2,。X 的前半段和 Y 的后半段长度显然为 n + 1 2 \frac{n + 1}{2} 2n+1,所以我们可以枚举并累加所有的 f n + 1 2 , i 2 f_{\frac{n + 1}{2},i}^2 f2n+1,i2。偶数序列同理枚举累加所有的 f n 2 , i 2 f_{\frac{n}{2},i}^2 f2n,i2。所以这个并集的方案数为: ∑ f n + 1 2 , i 2 × ∑ f n 2 , i 2 \sum f_{\frac{n + 1}{2},i}^2 \times \sum f_{\frac{n}{2},i}^2 ∑f2n+1,i2×∑f2n,i2。
把总方案数减掉并集的方案数就是答案,即 A n s w e r = 2 × ∑ f n , i 2 − ∑ f n + 1 2 , i 2 × ∑ f n 2 , i 2 Answer=2 \times \sum f_{n,i}^2-\sum f_{\frac{n + 1}{2},i}^2 \times \sum f_{\frac{n}{2},i}^2 Answer=2×∑fn,i2−∑f2n+1,i2×∑f2n,i2。
AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int n;
int F[1005][9005], S[15];
int Answer;
signed main() {
FAST_IO;
string s;
cin >> n >> s;
int length = s.size(), _max = -1;
for (register int i = 1; i <= length; ++i) S[i] = s[i - 1] - '0', _max = max(_max, S[i]);
F[0][0] = 1;
for (register int i = 1; i <= n; ++i)for (register int j = 0; j <= i * _max; ++j)for (register int k = 1; k <= length; ++k)if (j - S[k] >= 0) F[i][j] = F[i][j] + F[i - 1][j - S[k]] % 999983, F[i][j] %= 999983;
for (register int i = 0; i <= n * _max; ++i)Answer += 2 * F[n][i] * F[n][i], Answer %= 999983;
int answer_1 = 0, answer_2 = 0;
for (register int i = 0; i <= (n + 1) / 2 * _max; ++i) answer_1 += F[(n + 1) / 2][i] * F[(n + 1) / 2][i] % 999983, answer_1 %= 999983;
for (register int i = 0; i <= n / 2 * _max; ++i) answer_2 += F[n / 2][i] * F[n / 2][i] % 999983, answer_2 %= 999983;
Answer = Answer - answer_1 * answer_2 % 999983;
cout << (Answer + 999983) % 999983 << endl;
return 0;
}
小 F 了不起,大 F 夸自己。爆零就爆零,天天好心情。 小F了不起,大F夸自己。 爆零就爆零,天天好心情。 小F了不起,大F夸自己。爆零就爆零,天天好心情。