传智杯省赛(复赛)个人题解(231217场)
A小红劈字符串
题目:
小红拿到了一个字符串,她准备把这个字符串劈成两部分,使得第一部分的长度恰好是第二部分的两倍。你能帮她吗?
输入描述:
一个仅由小写字母构成的字符串,长度不超过 1 0 5 10^5 105。
输出描述:
如果无解,亲输出 − 1 -1 −1。
否则输出两个字符串,用空格隔开,代表劈完了的字符串。
示例1
输入
abc
输出
ab c
示例2
输入
ad
输出
-1
解题思路
先获取字符的长度 n n n,判断是否为 3 3 3的倍数,不是的话输出 − 1 -1 −1,因为非3的倍数完整切割成符合要求的两份。是 3 3 3的倍数则先将 n n n除 3 3 3获得 x x x,将字符串 s s s从 0 − 2 ∗ x 0-2*x 0−2∗x切开,再从 2 ∗ x − n 2*x-n 2∗x−n切开,就得到了答案
题解
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pss> vpss;
typedef vector<vi> vvi;
typedef queue <int> qi;
typedef queue <ll> ql;
typedef queue <pii> qpii;
typedef queue <psi> qpsi;
typedef priority_queue<int> pqi;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef unordered_map<int, int> umapii;
typedef unordered_map<string, int> umapsi;
const int N = 1e5 + 5;
void solve()
{
string s;
cin >> s;
int n = s.length();
if (n % 3 != 0)
{
cout << -1 << endl;
return;
}
int x = n / 3;
string a = s.substr(0, x * 2);
string b = s.substr(x * 2, n);
cout << a << " " << b << endl;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
B小红的数字分裂
题目:
小红有一个数组,她每次可以选择数组的一个元素 x x x,将这个元素分成两个元素 a a a和 b b b,使得 a + b = x a+b=x a+b=x。
请问小红最少需要操作多少次才可以使得数组的所有元素都相等。
输入描述:
第一行输入一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1≤n≤10^5) n(1≤n≤105)表示数组长度。
第二行输入 n n n个整数表示数组 a ( 1 ≤ a i ≤ 1 0 9 ) a(1≤a_i≤10^9) a(1≤ai≤109)。
输出描述:
输出一个整数表示答案
示例1
输入
2
2 4
输出
1
说明
操作1次,将4分成2和2,数组变成[2,2,2]
解题思路
先计算出数组 a a a中所有元素的最大公因数 m x G c d mxGcd mxGcd,然后统计数组中所有元素切成 m x G c d mxGcd mxGcd需要的次数。
题解
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pss> vpss;
typedef vector<vi> vvi;
typedef queue <int> qi;
typedef queue <ll> ql;
typedef queue <pii> qpii;
typedef queue <psi> qpsi;
typedef priority_queue<int> pqi;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef unordered_map<int, int> umapii;
typedef unordered_map<string, int> umapsi;
const int N = 1e5 + 5;
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
void solve()
{
ll n; cin >> n;
vl a(n);
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
ll mxGcd = a[0];
for (int i = 0; i < n; i++)
{
mxGcd=gcd(mxGcd, a[i]);
}
ll cnt = 0;
for (int i = 0; i < n; i++)
{
cnt += (a[i] / mxGcd) - 1;
}
cout << cnt << endl;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
C小红的字符串同构
题目:
有两个等长字符串 a a a和 b b b,如果对于所有的 a [ i ] − b [ i ] ( 1 ≤ i ≤ ∣ b ∣ ) a[i]-b[i](1≤i≤|b|) a[i]−b[i](1≤i≤∣b∣)为定值,则称它们为同构的。例如字符串" a b c d abcd abcd"和字符串“ e f g h efgh efgh"同构。
小红现在有一个字符串 a a a,她想获得一个满足以下两个条件的等长的字符串 b b b。请问 b b b一共有多少种?
- a a a和 b b b的每一位都不同,即 a [ i ] ! = b [ i ] ( 1 ≤ i ≤ ∣ b ∣ ) a[i]!=b[i](1≤i≤|b|) a[i]!=b[i](1≤i≤∣b∣)
- a a a和 b b b不同构
输入描述:
第一行输入一个字符串 a ( 1 ≤ ∣ a ∣ ≤ 1 0 5 ) a(1≤|a|≤10^5) a(1≤∣a∣≤105)。
输出描述:
输出一个整数表示答案。答案可能过大,需要模 1 0 9 + 7 10^9+7 109+7。
示例1
输入
a
输出
0
说明
所有长度为1的字符串于a都同构
示例2
输入
ab
输出
601
解题思路
观察同构规则,不难发现如果字符串 a a a于字符串 b b b同构,则 a a a于 b b b的每一位都不同,即条件2包含了条件1,所以我们只需要先计算出每一位都不同的字符串的数量,再减去同构字符串的数量就是答案。
对于字符串 a a a,计算每一位都不同的字符串的数量,即计算每一位除了它本身在这一位的字母的数量相乘,例如对于“ a b ab ab”来说,第一位除了 a a a有 25 25 25种字母,第二位除了 b b b有 25 25 25种字母,所以每一位都不同的字符串的数量为 25 × 25 = 625 25×25=625 25×25=625种。( 2 5 n ( 1 ≤ n ≤ 1 0 5 ) 25^n(1≤n≤10^5) 25n(1≤n≤105)比较大,要使用快速幂求)
计算字符串 a a a的重构字符串数量,先找出 a a a中最大的字符,再找出 a a a中最小的字符,字符域长度减去 a a a的值域长度就是重构字符串数量。例如对于“ a b ab ab”来说,最大的字符是 b b b,最小的字符是 a a a。值域长度就是 b − a + 1 = 2 b-a+1=2 b−a+1=2,字符域长度 26 − 2 = 24 26-2=24 26−2=24就是重构字符串数量。而对于“ a z az az”来说,重构字符串数量是 0 0 0。
题解
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pss> vpss;
typedef vector<vi> vvi;
typedef queue <int> qi;
typedef queue <ll> ql;
typedef queue <pii> qpii;
typedef queue <psi> qpsi;
typedef priority_queue<int> pqi;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef unordered_map<int, int> umapii;
typedef unordered_map<string, int> umapsi;
const int N = 1e5 + 5;
const int MOD = 1e9 + 7;
ll quickPow(ll x, ll n)
{
ll res = 1;
while (n)
{
if (n & 1)
res = res * x % MOD;
x = x * x % MOD;
n >>= 1;
}
return res;
}
ll cal(ll n)
{
ll res = 1;
while (n)
{
res = res * n % MOD;
n--;
}
return res;
}
void solve()
{
string s;
cin >> s;
int n = s.length();
ll ans = quickPow(25, n);
char mxChar = *max_element(s.begin(), s.end());
char mnChar = *min_element(s.begin(), s.end());
ll len = ll(mxChar - mnChar + 1);
ans = ans - (26 - len);
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
E
原题链接
题目:
一开始,你有一个空的线段集合。你需要处理q 个两种类型的操作:
+ l r
— 将线段 ( l , r ) (l, r) (l,r) 添加到集合中,- l r
— 从集合中删除恰好一个线段 ( l , r ) (l, r) (l,r)。保证该线段存在于集合中。
在每次操作后,你需要判断集合中是否存在相交的线段。(一对线段$ (l, r)$ 和$ (a, b)$ 不相交,如果不存在一个点 x 使得 l ≤ x ≤ r l ≤ x ≤ r l≤x≤r 并且 a ≤ x ≤ b a ≤ x ≤ b a≤x≤b。)
输入描述:
每个测试用例的第一行包含一个整数 q ( 1 ≤ q ≤ 1 0 5 ) q (1 ≤ q ≤ 10^5) q(1≤q≤105) — 操作的次数。
接下来的 q 行描述了两种操作类型。如果是添加操作,则格式为 + l r
。如果是删除操作,则格式为 - l r
(
1
≤
l
≤
r
≤
1
0
9
)
(1 ≤ l ≤ r ≤ 10^9)
(1≤l≤r≤109)。
输出描述:
在每次操作后,如果集合中存在相交的线段,则打印 “Yes”,否则打印 “No”。
示例1:
输入
4
+ 1 2
+ 4 5
+ 3 4
- 4 5
输出
No
No
Yes
No
解题思路
先插入一个
1
−
1
0
9
1-10^9
1−109的区间,全部赋值为0。+ l r
插入区间就相当于做区间加法,区间
[
l
,
r
]
+
1
[l,r]+1
[l,r]+1,- l r
删去区间去相当于区间减法
[
l
,
r
]
−
1
[l,r]-1
[l,r]−1。每操作完一次之后遍历一遍区间,检查是否有点
≥
2
≥2
≥2。我使用的是珂朵莉树来维护区间(珂朵莉树天下第一),具体原理可以看我的博客基于STL库set容器实现的珂朵莉树。
题解:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pss> vpss;
typedef vector<vi> vvi;
typedef queue <int> qi;
typedef queue <ll> ql;
typedef queue <pii> qpii;
typedef queue <psi> qpsi;
typedef priority_queue<int> pqi;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef unordered_map<int, int> umapii;
typedef unordered_map<string, int> umapsi;
const int N = 5e5 + 5;
int n, q, l, r;
char opt;
struct node
{
int _left, _right;
mutable int _val;
node(int L = 0, int R = -1, int V = 0) :_left(L), _right(R), _val(V) {}
bool operator < (const node& x) const
{
return _left < x._left;
}
};
set<node> s;
auto split(int p)
{
auto iter = s.lower_bound(node(p));
if (iter != s.end() && iter->_left == p)
return iter;
iter--;
int l = iter->_left;
int r = iter->_right;
int v = iter->_val;
s.erase(iter);
s.insert(node(l, p - 1, v));
return s.insert(node(p, r, v)).first;
}
void add(int l, int r, char opt)
{
auto itR = split(r + 1);
auto itL = split(l);
int v = opt == '+' ? 1 : -1;
for (auto iter = itL; iter != itR; iter++)
{
iter->_val += v;
}
}
bool ask(int l, int r)
{
auto itR = split(r + 1);
auto itL = split(l);
for (auto iter = itL; iter != itR; iter++)
{
if (iter->_val > 1)
return true;
}
return false;
}
void solve()
{
cin >> q;
const int L = 1;
const int R = 1e9 + 5;
s.insert(node(L, R, 0));
while (q--)
{
cin >>opt>> l >> r;
add(l, r, opt);
if (ask(L, R))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}