牛客周赛 Round 108 CDEF题解
C、小苯的数字合并
题意:
小苯有一个长度为 $ n $ 的数组 $ a_1, a_2, \ldots, a_n $,他可以对 $ a $ 进行任意次“数字合并”操作,具体地,一次数字合并操作描述为:
- 选择一个下标 $ i $ ($ 1 \leq i < |a| $),将 $ a_i $ 和 $ a_{i+1} $ 合并为一个数字,结果为两个的和 $ a_i + a_{i+1} $。合并后数组长度减 1,下标按新数组重新编号。
现在小苯可以进行任意次上述操作,他想知道他可以得到多少种本质不同结果数组,请你帮他数一数吧。换句话说,在可以进行任意次操作的情况下,所有可能得到的数组 $ a $ 有多少种本质不同的模样。由于答案可能很大,请将答案对 $ 998,244,353 $ 取模后输出。
思路:
对于任意的合并操作,数组一定改变。
数组长度:2 3 ... n
res: 2 4 ... \(2^{n - 1}\)
直接输出\(2 ^ {n - 1}\)即可
代码
cout << pow_mod(2, n - 1) << '\n';
D、小苯的子序列权值
题意:
小苯有一个长度为 \(n\) 的序列 \(a_1, a_2, \ldots, a_n\),他认为一个序列的权值为:序列中所有数字的按位与。
现在小苯想知道所有的非空(显然一共 \(2^n - 1\) 个)的子序列\footnote{子序列是指从原序列中选取若干个元素(可以不连续)形成的序列} 中,有多少个子序列的权值是偶数,请你帮他算一算吧。由于答案可能很大,请将答案对 \(998\,244\,353\) 取模后输出。
思路:
考虑用所有子序列的情况减去子序列为奇数的情况
子序列为奇数的情况:序列中所有元素均为奇数,情况有:\(2^{cnt - 1}\)种 \({cnt为奇数的个数)\)
代码
cout << (ksm (2, n) - ksm (2, numn) +2 * mod) % mod << "\n";
E、小苯的数字合并
题意:
小苯发现了一些「有趣的」数字,即:数字本身是个完全平方数,且其各个数位之和也是个完全平方数!例如 \(2025\) 本身就是个完全平方数,同时其各个数位之和:\(2 + 0 + 2 + 5 = 9\) 也是个完全平方数,因此小苯认为 \(2025\) 就是个「有趣的」数字。
现在小苯有一个长度为 \(n\) 的序列 \(a_1, a_2, \ldots, a_n\),他可以对 \(a\) 做任意次以下操作:
选择两个不同的下标 \(i, j\) (\(1 \leq i, j \leq n; i \neq j\)),满足 \(a_i \geq 2\),随后将 \(a_i\) 减去 \(1\),\(a_j\) 加上 \(1\)。
他想知道,自己至多可以把 \(a\) 中多少个数字变成「有趣的」数字,请你帮他算一算吧
思路:
因为1也是有趣的数字,所以前n-1位均填1,则答案至少为n-1。现在考虑能否填满,即在符合条件的数字中选择n个是否能够刚好填满,考虑dp即可。
dp[i, j] 使用总和为i的数,能否填j个数字
代码
#include<bits/stdc++.h>
#define ll long long
#define ce cerr
#define ull unsigned long long
#define lll __int128
#define PII pair<int, int>
#define PLL pair<long ,long>
using namespace std;
const int inf = 0x3f3f3f3f;
const ll iinf = 1e18;
//cin.ignore(std::numeric_limits< streamsize >::max(), '\n');
int t;
vector<int> vec;
int n;
vector<vector<int> > dp (2e4 + 1, vector<int> (105, 0));
void init () {
vec.push_back (inf);
for (int i = 1; i <= 20000; ++i) {
int q = sqrt (i);
if (q * q == i) {
int temp = i;
int res = 0;
while (temp) {
res += temp % 10;
temp /= 10;
}
q = sqrt (res);
if (q * q == res) {
vec.push_back (i);
}
}
}
int nn = vec.size ();
// dp : 使用总和为i的数,能否组成j个数字
//for (auto i : vec) ce << i << " ";
dp[0][0] = 1;
for (int i = 1; i <= 2e4; ++i) {
for (int j = 1; j <= 104; ++j) {
for (int k = 1; k <= nn - 1 && i - vec[k] >= 0; ++k) {
dp[i][j] = dp[i][j] | dp[i - vec[k]][j - 1];
}
}
}
}
void solve() {
cin >> n;
int sum = 0;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
sum += x;
}
if (dp[sum][n] == 1) {
cout << n << "\n";
}else{
cout << n - 1 << "\n";
}
}
int main() {
ios::sync_with_stdio (false);
cin.tie(NULL);
cout.tie(NULL);
t = 1;
cin >> t;
init ();
while (t --) {
solve();
}
return 0;
}