程设2021期末题E:数字构造

原题:http://cxsjsx.openjudge.cn/2021finalpractise/E/

描述

火山宝打算造一个 n 位的十进制数字出来。
对于 1 到 n 中的每一个 i,火山宝可以从 xi,1, ..., xi,ki 这 ki 个 0-9 的数字中选择一个作为 ai
在选择结束后,a1a2...an 形成了一个 n 位的十进制数——这就是火山宝造出来的数。
你需要帮火山宝计算他能造出的数中,有多少个是 3 的倍数。

输入

第一行输入一个整数 n(1 ≤ n ≤ 18),表示数字的位数。
接下来 n 行,每行第一个整数 ki (1 ≤ ki ≤ 10),表示第 i 中候选的数字数量。接着是 ki 个两两不同的 0-9 范围内的数字 xi,1, ..., xi,ki
输入保证 0 不是第一位的可选项。

输出

你需要输出一行一个整数,表示火山宝能造出的数字中,3 的倍数的数量。

样例输入

样例输入1:
2
5 5 6 7 8 9
5 0 1 2 3 4

样例输入2:
5
9 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9

样例输出

样例输出1:
9

样例输出2:
30000

提示

样例1能造出来的 3 的倍数有 51, 54,60,63,72,81,84,90, 93。

解法

思路:要是把每个n位的十进制数都算出来然后判断是否是3的倍数,这肯定会超时。

根据数论,由于10与1模3同余,一个n位的十进制数是3的倍数等价于这些十进制数的和是3的倍数。

而且可以用等价类的思想来计算。每行分别计算等价类。

重要的坑:结果可能超过int的范围,所以要用long来存,不然会WA。

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 int num[20][10];
 5 int k[20];
 6 int mod[20][3] = {};
 7 int main() {
 8     int n;
 9     cin >> n;
10     for (int i = 0; i < n; i++) {
11         cin >> k[i];
12         for (int j = 0; j < k[i]; j++){
13             cin >> num[i][j];
14             mod[i][num[i][j] % 3]++;
15         }
16     }
17     long result[3] = {};
18     for (int i = 0; i < 3; i++)
19         result[i] = mod[0][i];
20     for (int i = 1; i < n; i++) {
21         long temp0 = result[0], temp1 = result[1], temp2 = result[2];
22         result[0] = temp0 * mod[i][0] + temp1 * mod[i][2] + temp2 * mod[i][1];
23         result[1] = temp0 * mod[i][1] + temp1 * mod[i][0] + temp2 * mod[i][2];
24         result[2] = temp0 * mod[i][2] + temp1 * mod[i][1] + temp2 * mod[i][0];
25     }
26     cout << result[0] << endl;
27     return 0;
28 }

 

posted @ 2021-07-19 21:17  永远是个小孩子  阅读(638)  评论(0)    收藏  举报