CF系列题解
Codeforces Round #785 (Div. 2)
题目
A. Subtle Substring Subtraction
原题链接
A. Subtle Substring Subtraction
题意
Alice 和 Bob 玩游戏,给定一个由小写字母组成的字符串,每次 Alice 可以选择长度为偶数的子串,Bob 可以选择长度为奇数的子串,其中 a
对应
1
1
1 分,b
对应
2
2
2 分,以此类推。两人均采用最佳策略且 Alice 先手,问每轮的胜利者是谁并且得分相差绝对值是多少。
输入格式
第一行包含一个整数
t
(
1
≤
t
≤
5
⋅
1
0
4
)
t (1≤t≤5⋅10^4)
t(1≤t≤5⋅104) ,表示有t组测试数据。
每个测试数据第一行包含一个字符串
s
(
1
≤
∣
s
∣
≤
2
⋅
1
0
5
)
s (1≤|s|≤2⋅10^5)
s(1≤∣s∣≤2⋅105)。
字符串总长度不超过
2
⋅
1
0
5
2⋅10^5
2⋅105
输出格式
胜利者的名字以及二者的分数差的绝对值
输入样例:
5
aba
abc
cba
n
codeforces
输出样例:
Alice 2
Alice 4
Alice 4
Bob 14
Alice 93
题解
思路
由于采用最佳策略,因此倘若字符串长度为偶数,Alice 一定会直接拿完,否则的话其会舍弃头或尾的字符(取决于哪个大)。
细节见代码。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve()
{
string s;
cin >> s;
int n = s.size();
int a = 0, b = 0;
vector<int> q(n + 1);
for (int i = 1; i <= n; i ++ ) q[i] = s[i - 1] - 'a' + 1;
// 此处直接用前缀和做了,直接枚举也是可以的
for (int i = 1; i <= n; i ++ ) q[i] += q[i - 1];
if (n % 2) {
int t = max(q[n] - q[1], q[n - 1]);
a += t;
b += q[n] - t;
} else {
a += q[n];
}
if (a > b) {
cout << "Alice " << abs(a - b) << "\n";
} else {
cout << "Bob " << abs(a - b) << "\n";
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
B - A Perfectly Balanced String?
原题链接
B - A Perfectly Balanced String?
题意
给定一个字符串 s s s,我们规定 ( t , u , v ) (t,u,v) (t,u,v),其中 t t t 为 s s s 的子串, u u u 和 v v v 为 s s s 的其中一个字符,问对于 s s s 的所有类似的三元组,是否满足 u u u 和 v v v 在 t t t 中出现的次数之差的绝对值小于等于 1 1 1。
输入格式
第一行包含一个整数
t
(
1
≤
t
≤
2
⋅
1
0
4
)
t (1≤t≤2⋅10^4)
t(1≤t≤2⋅104) ,表示有t组测试数据。
每个测试数据包含一个字符串
s
(
1
≤
∣
s
∣
≤
2
⋅
1
0
5
)
s (1≤|s|≤2⋅10^5)
s(1≤∣s∣≤2⋅105)。
字符串长度的总和不超过
2
⋅
1
0
5
2⋅10^5
2⋅105。
输出格式
若能满足要求输出 YES
,否则输出 NO
。
输入样例:
5
aba
abb
abc
aaaaa
abcba
输出样例:
YES
NO
YES
YES
NO
题解
思路
倘若字符串 s s s 中存在 c n t cnt cnt 个不同的字母,那么对于原串的前缀,即 [ 1 , c n t ] [1,cnt] [1,cnt] 中每个字母必须出现一次,且对于 c n t cnt cnt 之后的部分,一定要是重复出现 [ 1 , c n t ] [1,cnt] [1,cnt] 这一段的内容,即 [ 1 , c n t ] = [ c n t + 1 , 2 × c n t ] [1, cnt] = [cnt+1, 2×cnt] [1,cnt]=[cnt+1,2×cnt],倘若不满足其中一个条件,即为不合法。
求不同元素和对于 [ 1 , c n t ] [1,cnt] [1,cnt] 的判重偷懒用的全是 s e t set set。
无证明。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve()
{
string s;
cin >> s;
set<char> S;
for (int i = 0; i < s.size(); i ++ ) S.insert(s[i]);
int cnt = S.size();
set<int> w;
for (int i = 0; i < cnt; i ++ ) w.insert(s[i]);
if (w.size() != cnt) {
cout << "NO\n";
return;
}
for (int i = cnt; i < s.size(); i ++ ) {
if (s[i % cnt] != s[i]) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
C. Palindrome Basis
原题链接
题意
给定一个数 n n n,他能被若干个回文数相加而成,问由多少种方案。
回文数:1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,101,111...
输入格式
第一行包含一个整数
t
(
1
≤
t
≤
1
0
4
)
t (1≤t≤10^4)
t(1≤t≤104) ,表示有t组测试数据。
每个测试数据包含一个整数
n
(
1
≤
n
≤
4
⋅
1
0
4
)
n (1≤n≤4⋅10^4)
n(1≤n≤4⋅104)。
输出格式
方案数
输入样例:
2
5
12
输出样例:
7
74
题解
思路
完全背包求方案,预处理出来即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int P = 1e9+7;
using i64 = long long;
// assume -P <= x < 2P
int norm(int x) {
if (x < 0) {
x += P;
}
if (x >= P) {
x -= P;
}
return x;
}
template<class T>
T power(T a, int b) {
T res = 1;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
struct Z {
int x;
Z(int x = 0) : x(norm(x)) {}
int val() const {
return x;
}
Z operator-() const {
return Z(norm(P - x));
}
Z inv() const {
assert(x != 0);
return power(*this, P - 2);
}
Z &operator*=(const Z &rhs) {
x = i64(x) * rhs.x % P;
return *this;
}
Z &operator+=(const Z &rhs) {
x = norm(x + rhs.x);
return *this;
}
Z &operator-=(const Z &rhs) {
x = norm(x - rhs.x);
return *this;
}
Z &operator/=(const Z &rhs) {
return *this *= rhs.inv();
}
friend Z operator*(const Z &lhs, const Z &rhs) {
Z res = lhs;
res *= rhs;
return res;
}
friend Z operator+(const Z &lhs, const Z &rhs) {
Z res = lhs;
res += rhs;
return res;
}
friend Z operator-(const Z &lhs, const Z &rhs) {
Z res = lhs;
res -= rhs;
return res;
}
friend Z operator/(const Z &lhs, const Z &rhs) {
Z res = lhs;
res /= rhs;
return res;
}
friend istream& operator>> (istream& is, Z& z) {
is >> z.x;
z.x = (z.x % P + P) % P;
return is;
}
friend ostream& operator << (ostream& out,Z& z) {
out << z.x;
return out;
}
};
const int N = 40010;
int w[N], cnt;
Z dp[N];
bool check(int x)
{
string s = to_string(x);
for (int i = 0, j = s.size() - 1; i < s.size(); i ++ , j -- ) {
if (s[i] != s[j]) {
return false;
}
}
return true;
}
void init()
{
for (int i = 1; i < N; i ++ ) {
if (check(i)) {
w[ ++ cnt] = i;
}
}
dp[0] = 1;
for (int i = 1; i <= cnt; i ++ ) {
for (int j = w[i]; j < N; j ++ ) {
dp[j] += dp[j - w[i]];
}
}
}
void solve()
{
int n;
cin >> n;
cout << dp[n] << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
D. Lost Arithmetic Progression(待补)
原题链接
D. Lost Arithmetic Progression
题意
输入格式
输出格式
输入样例:
8
-3 1 7
-1 2 4
-9 3 11
0 6 3
2 5 5
7 5 4
2 2 11
10 5 3
0 2 9
2 4 3
-11 4 12
1 12 2
-27 4 7
-17 8 2
-8400 420 1000000000
0 4620 10
输出样例:
0
10
-1
0
-1
21
0
273000
题解
思路
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using i64 = long long;
constexpr int P = 1e9 + 7;
void solve()
{
int st_b, d_b, len_b;
int st_c, d_c, len_c;
cin >> st_b >> d_b >> len_b >> st_c >> d_c >> len_c;
int ed_b = st_b + d_b * (len_b - 1);
int ed_c = st_c + d_c * (len_c - 1);
// C在B中都出现过需要满足 范围 公差可以整除 首项之差
if (!(st_b <= st_c && ed_c <= ed_b) || d_c % d_b != 0 || (st_c - st_b) % d_b != 0) {
cout << "0\n";
} else if (st_c - d_c < st_b || ed_c + d_c > ed_b) { // 若C首项的前一项或者末项的后一项不在B的范围,则说明可以无限延申
cout << "-1\n";
} else {
int ans = 0;
// d_c的因数即为d_a
for (i64 d_a = 1; d_a * d_a <= d_c; d_a ++ ) {
if (d_c % d_a == 0) {
// 可以分别向左右扩展d_c/d_a个
if (lcm(d_a, d_b) == d_c) {
(ans += (d_c / d_a) * (d_c / d_a)) %= P;
}
if (d_c / d_a != d_a && lcm(d_c / d_a, d_b) == d_c) {
(ans += d_a * d_a) %= P;
}
}
}
cout << ans << "\n";
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}