牛客周赛 Round 110 E,F题解
E、小苯的数字变换
题意:
小苯在研究一种特殊的数字变换。对于一个正整数 \(x\),定义一个数字的“根”为不断将其各位数字相加直到得到个位数。例如:
\[\text{根}(38) = 3 + 8 = 11 \rightarrow 1 + 1 = 2
\]
\[\text{根}(999) = 9 + 9 + 9 = 27 \rightarrow 2 + 7 = 9
\]
现在给定一个数字串 \(x\),请你求出:所有 \(x\) 的连续子区间代表的十进制数字(去掉前导 0 后)的 “根” 之和。
思路:
考虑\(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;
void solve() {
string s;
cin >> s;
int n = s.size ();
s= ' ' + s;
vector<ll> a (n + 1);
vector<vector<ll> > dp (n + 1, vector<ll> (10, 0));
for (int i = 1; i <= n; ++i) {
a[i] = (int) s[i] - '0';
}
// dp[i][j] : 第i个数字结尾,“根”之和为j的连续子区间的个数
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= 9; ++j) {
int num = s[i] - '0';
int temp = num + j;
if (temp >= 10) temp -= 9;
dp[i][temp] += dp[i - 1][j];
}
dp[i][a[i]] ++;
}
ll res = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= 9; ++j) {
res += dp[i][j] * j;
}
}
cout << res << "\n";
}
int main() {
ios::sync_with_stdio (false);
cin.tie(NULL);
cout.tie(NULL);
t = 1;
cin >> t;
while (t --) {
solve();
}
return 0;
}
F、小苯的序列合并
题意:
给定长度为 \(n\) 的序列 \(a\),你可以对 \(a\) 做如下操作任意次:
- 选择一个下标 \(i \ (1 \leq i < |a|)\),将 \(a_i\) 与 \(a_{i+1}\) 合并起来,结果为 \(a_i \oplus a_{i+1}\)。(其中 \(\oplus\) 表示按位异或运算符,\(|a|\) 表示 \(a\) 当前的长度。)
所有操作结束后,小苯希望你最大化最终 \(a\) 中所有数字的按位与,即 AND(&)值,请你算一下这个最大值是多少吧。
思路:
关键点:最优解最多只会划分成两段(进行&的段数\(\leq 2\))
对于三个数字一定有:\(x_1 \oplus x_2 \oplus x_3 >= x_1 \& x_2 \& x_3\)(这里异或顺序不定)
所以,对于大于等于三段的分段方法,一定能够通过相邻三个数字之间不断异或,得到最终一个或者两个数字进行与运算
代码
#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;
void solve() {
int n;
cin >> n;
vector<ll> a (n + 1);
vector<ll> b (n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
b[i] = b[i - 1] ^ a[i];
}
ll res = b[n];
for (int i = 0; i <= n; ++i) {
//ce << b[i] <<" " << (b[n] ^ b[i]) << "\n";
res = max (res, b[i] & (b[n] ^ b[i]));
}
cout << res << "\n";
}
int main() {
ios::sync_with_stdio (false);
cin.tie(NULL);
cout.tie(NULL);
t = 1;
cin >> t;
while (t --) {
solve();
}
return 0;
}