Educational Codeforces Round 147 (Rated for Div. 2)题解
A.Matching
题意
给你一个只包含数字或者问号的字符串,问你将问号替换为数字,得到的合法数字的方案,不能有前导零。
解题思路
特判一个个字符,假如第一个字符是 '0'
,那么答案一定是 0
,假如第一个字符是 '?'
,那么第一个字符的贡献是 9
(因为不能是 '0'
),其余字符的贡献是10
,然后把所有贡献相乘。
AC_Code
//
// Created by liuhao on 2023/10/7.
//
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
void solve()
{
string s;
cin>>s;
int ans=1;
if(s[0]=='?')ans=9;
if(s[0]=='0')ans=0;
for(int i=1;i<s.size();i++)
{
if(s[i]=='?')ans*=10;
}
cout<<ans<<endl;
}
signed main() {
ios;
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B.Sort the Subarray
题意
给你两个序列 a,a'
,a'
是由 a
排序一个子数组得到的,但是你不知到排序了哪个子数组,求可能得最长的子数组是哪个,输出 l,r
代表子数组 a[l...r]
。
解题思路
我们可以将 a
分为多个有序的子数组,比如 [3,2,1,3,4,5,6,7,8]
可以分为 [[3],[2],[1,3,4,5,6,7,8]]
,然后我们需要找到哪个子数组和原数组不同,那么这个子数组就是一定有一部分被排了序,题目中要求的最长的子数组的就是这个子数组。
AC_Code
//
// Created by liuhao.
//
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define vii vector<vector<int>>
void solve()
{
int n;
cin>>n;
vector<int>a(n+1);
vector<int>b(n+1);
for (int i = 1; i <= n; i++) {
cin>>a[i];
}
for (int i = 1; i <= n; i++) {
cin>>b[i];
}
vector<vector<int>>ans;
int la=1;
for(int i=2;i<=n;i++)
{
if(b[i]<b[i-1])
ans.emplace_back(b.begin()+la,b.begin()+i),la=i;
}
ans.emplace_back(b.begin()+la,b.begin()+n+1);
int cnt=1;
for(auto i :ans)
{
for(int j=0;j<i.size();j++)
{
if(b[cnt+j]!=a[cnt+j])
{
cout<<cnt<<" "<<cnt+i.size()-1<<endl;
return;
}
}
cnt+=i.size();
}
}
signed main()
{
ios;
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C.Tear It Apart
题意
给你一个字符串,每次可以删除一些字符,但是在同一次中,删除的字符不能相邻,求将字符串删除至所有字符相同的最少次数。
解题思路
假如我要保留一个字符 ch
,那么我删除就不会删除 ch
,所以这个字符串可以被 ch
分为若干个子串,这些子串的删除互不影响,所以我们只需要计算删除最长的子串的次数即可,那么怎么确定保留哪个字符呢,枚举就可以了,最多就枚举 26
次,然后取最小值。
AC_Code
//
// Created by liuhao.
//
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define vii vector<vector<int>>
void solve()
{
string s;
cin>>s;
s=" "+s;
int ans=0x3f3f3f3f;
int n=s.size()-1;
for(int i=0;i<26;i++) {
char c = 'a' + i;
int la = 0;
int cnt = 0;
int len = 0;
int flag=0;
for (int j = 1; j <= n; j++) {
if (s[j] != c) {
cnt++;
} else {
flag=1;
cnt = 0;
}
len = max(len, cnt);
}
cnt = 0;
while (len) {
len -= (len - 1) / 2 + 1;
cnt++;
}
if(flag)
{
ans = min(ans, cnt);
}
}
cout<<ans<<endl;
}
signed main()
{
ios;
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D.Black Cells
题意
初始你在 0
的位置,你有 3
种操作
- 往右走一格
- 按下
shift
- 松开
shift
,然后在按下shift
过程中经过的格子都会变成黑色。
现在需要你用这些操作给 k
个格子染色,并且染色的格子必须至少在一个给定的 n
个区间中的一个,求最少的操作数。
解题思路
假如我已经走到了第 i
个区间的位置,并且到这个位置,所有区间的长度和恰好超过了 k
,那么我现在是不是可以考虑丢掉前面的一些区间来保证我能继续往下走,现在考虑丢掉哪些好,毋庸置疑的是区间长度最小的,因为区间小的会导致你需要更多次数的按下和释放 shift
,并且你已经走到这个区间了,所以你就不用考虑第一种操作带来的操作次数,我们可以使用 set
或者优先队列来实现这个过程。
AC_Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve() {
int n, k;
cin >> n >> k;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
int res = 1e18, sum = 0;;
priority_queue<int, vector<int>, greater<int>> q;
for (int i = 1; i <= n; i++) {
sum += b[i] - a[i] + 1;//加上染色的长度
q.push(b[i] - a[i] + 1);//插入区间
while (sum >= k) {
int t = k - (sum - (b[i] - a[i] + 1)) + a[i] - 1;
res = min(res, 2 * ((int) q.size()) + t);
sum -= q.top();
q.pop();
}
}
if (res != 1e18) {
cout << res << '\n';
} else {
cout<<-1<<endl;
}
}
signed main() {
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}