题目 | 满意的集合
牛客小白月赛43
E - 满意的集合
https://ac.nowcoder.com/acm/contest/11220/E
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
有数字
"满意的集合" 定义:选出的数存在一种排列方式,其拼接起来后表示的十进制整数,能被
两个集合相同,当且仅当集合元素个数相同,且排序后对应数字相同,例如
空集合看作
输入描述:
输入一行,包括个整数 ,分别表示数字 的个数, 。
输出描述:
输出一行,表示”满意的集合”的个数,答案对取模。
示例1
输入
1 1 1 0 0 0 0 0 0
输出
4
说明
全部的数字集合。可能的集合有 。其中“满意的集合“有 共 个。
我的笔记
分析
首先简化题意,将“排列
然后进行分析,本题可使用动态规划算法,将其转化为递推。递推第 0 层就是数字集合里不选任何数的情况,第 1 层就是数字集合里只选 1 的情况,第 2 层就是数字集合里只选 1、2 的情况,第 3 层就是数字集合里只选 1、2、3 的情况……(每层递推都允许不选任何数)
然后得到以下 DP 写法:
// TLE Version DP
for (int i = 1; i <= 9; i++) // 递推层数,直到推到第9层,即获得符合题意的答案
{
for (int j = 0; j <= cnt[i]; j++) // 遍历选0个i、1个i、2个i……直到全选的所有情况
{
for (int k = 0; k < 3; k++) // 递推模为0、为1、为2的结果
{
dp[i][(j * i + k) % 3] += dp[i - 1][k];
dp[i][(j * i + k) % 3] %= MOD; // MOD为1e9+7
}
}
}
但可以发现,该方法时间复杂度极高,为
进一步分析,每个数选
(0 * 2) % 3 = 0, (1 * 2) % 3 = 2, (2 * 2) % 3 = 1,
(3 * 2) % 3 = 0, (4 * 2) % 3 = 2, (5 * 2) % 3 = 1……
这样我们就能把
源码
#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
int main(void)
{
int cnt[10];
for (int i = 1; i <= 9; i++)
{
cin >> cnt[i];
}
long long dp[10][3];
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= 9; i++)
{
int mod_1 = (0 * i) % 3, mod_2 = (1 * i) % 3, mod_3 = (2 * i) % 3;
int cnt_mod_1 = cnt[i] / 3 + 1, cnt_mod_2 = (cnt[i] + 1) / 3, cnt_mod_3 = (cnt[i] + 2) / 3;
for (int j = 0; j < 3; j++)
{
dp[i][(j + mod_1) % 3] += dp[i - 1][j] * cnt_mod_1;
dp[i][(j + mod_2) % 3] += dp[i - 1][j] * cnt_mod_2;
dp[i][(j + mod_3) % 3] += dp[i - 1][j] * cnt_mod_3;
dp[i][(j + mod_1) % 3] %= MOD;
dp[i][(j + mod_2) % 3] %= MOD;
dp[i][(j + mod_3) % 3] %= MOD;
}
}
cout << dp[9][0] << endl;
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi