Codeforces Global Round 20
Codeforces Global Round 20
A
略
B
题意
定义 好串 是由一段长度大于0的连续的前缀A和一个B组成的字符串,比如AB,AAB,AAAB...
现在给一个串 \(s\) 问可不可以将一个空串通过若干次在任意的位置插入任意好串构造出来。
思路
\(s\) 的任意前缀 \(A\) 的个数一定多于 \(B\) 的个数。
假设存在一个前缀 \(cnt_B > cnt_A\) ,根据鸽巢原理一定有一个好串要多分一个 \(B\) 从而变得不好。
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
string s;
cin >> s;
if(s.size() == 1 || s[0] == 'B' || s.back() == 'A') {
cout << "NO\n";
return;
}
int N = s.size();
bool havea = 0,haveb = 0;
for(int i = 0;i < N;i ++) {
if(s[i] == 'A') havea = 1;
if(s[i] == 'B') haveb = 1;
}
// 1 & 0 == 0
if(!(havea & haveb)) {
cout << "NO\n";
return;
}
// a < b
int a = 0,b = 0;
for(int i = 0;i < N;i ++) {
a += s[i] == 'A';
b += s[i] == 'B';
if(a < b) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
C
题意
一个序列 \(a\) 如果满足 \(a_i = a_{i+ 1}\) ,该序列权值加一。
每次我们可以将相邻两个数字置为任意一个数 \(x\) 。
问最小几次操作后序列权值 小于等于1
思路
如果权值本身小于等于1输出0
看序列权值大于1的。这个操作每次本身也会使得权值加一,所以每次操作必须要有重叠来消除本身对答案的影响,所以找到操作的起点和终点做差就是答案。
注意特判差为0。
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N;
cin >> N;
vector<int> a(N + 1);
for(int i = 1;i <= N;i ++) {
cin >> a[i];
}
int ans = 0;
int cnt = 0;
for(int i = 1;i < N;i ++) {
if(a[i] == a[i + 1]) {
cnt ++;
}
}
if(cnt <= 1) {
cout << ans << endl;
}else {
int start = 0;
for(int i = 1;i < N;i ++) if(a[i] == a[i + 1]){
start = i;
break;
}
int f = 0;
for(int i = 2;i <= N;i ++) if(a[i] == a[i + 1]) {
f = i;
}
ans = f - start - 1;
cout << max(1ll,ans) << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
D
题意
有一个序列 \(a\) ,每次可以选择一段区间 \([l,r]\) ,保证\(a_l = a_r\),左移这个区间。
现给一个序列 \(b\) ,问是否可以通过上述操作构造出来。
思路
贪心+双指针
起始状态和终止状态都很明确,不妨反向考虑从 \(b\) 如何构造出 \(a\) 。
相应的,操作变为如果 \(b\) 中出现 \(b_i = b_{i + 1}\) ,那么我们就可以将 \(b_i\) 删去并在前面任意一个地方插入一个 \(b_i\) 。
从后往前考虑,如果出现 \(b_i = b_{i + 1}\) ,我们就有了一个可以自由插入的 \(b_i\) ,我们贪心的将其保存起来。
那么可以用 \(i,j\) 两个指针从后往前考察 \(a\) , \(b\) 。
当 \(b_{j - 1} = b_{j}\) ,就把 \(b_{j - 1}\) 存起来。\(j\) 前移。
当 \(a_i = b_j\) ,匹配不管它们指针前移
当 $a_i \neq b_j $ ,不匹配,我们就找之前存起来的 \(b_j\) 是否有和 \(a_i\) 匹配的,有就继续匹配,没有就说明无法构造。
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N; cin >> N;
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];
multiset<int> s;
for(int i = N,j = N;i > 0 && j > 0;) {
if(b[j] == b[j - 1]) {// 2 1 2 2 2 2 1 2 2 2 2
s.insert(b[j - 1]);
j --;
}else if(a[i] == b[j]) i -- , j --;
else if(a[i] != b[j]) {
if(s.count(a[i])) {
s.erase(s.lower_bound(a[i]));
i --;
}else {
cout << "NO\n";
return;
}
}
}
cout << "YES\n";
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
E
题意
有 \(n\) 个长度未知的字符串数组,你可以进行最多 $n + 30 $ 次询问。
对于每次询问,你可以定一个宽度 $ w $,如果这个宽度比最长的字符串还要短,则会返回 $0 $ ;否则,在两个相邻字符串之间至少间隔一个空格、每行的长度不超过所给的宽度的情况下,所能够得到的最小的长度 \(h\)。
求该字符串数组能够得到的 \(h ∗ w ≠ 0\) 的情况下的最小值。
思路
恶心交互题
一眼二分,但显然操作此时不达标,看到 \(30 + n\) ,想到先对行数为 \(1\) 进行二分,再暴力枚举行数。
但我们并不知道行数为 \(h\) 时对应的宽度 \(w\) 。
设总共格子数(也就是题中的面积)为 \(S\)
注意到 \(S\) 一定要是 \(h\) 的倍数,所以 \(h\) 行时的宽度一定是 $ \lfloor \frac{S}{h} \rfloor$ 。
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
// #define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N;
cin >> N;
auto ask = [&](int x) {
cout << "? " << x << endl;
int ans;cin >> ans;
return ans;
};
int l = 0,r = 2000 * 2000 + 1;
while(l + 1 < r) {
int mid = l + r >> 1;
int x = ask(mid);
if(x > 1 || x == 0) l = mid;
else r = mid;
}
int onew = r;
int ans = onew;
for(int i = 2;i <= N;i ++) {
int x = ask(onew / i);// Length = x
if(x) ans = min(ans,x * (onew / i));
}
cout << "! " << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
//int T;cin>>T;
//while(T--)
solve();
return 0;
}
F
题意
给一个序列 \(a\) 。可以交换任意两个数。
现在构造一个序列 \(b\) ,使得其变为 \(a\) 的最少交换次数最大。
思路
一个神奇的结论排序算法-最少交换次数证明_玉曦的博客-CSDN博客_交换次数最少的排序算法
让环最少,也就是最多数字出现次数。
然后关于如何构造的问题,还没弄太懂···
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N;
cin >> N;
vector<int> a(N + 1),cnt(N + 1);
for(int i = 1;i <= N;i ++) cin >> a[i], cnt[a[i]] ++;
int mx = *max_element(cnt.begin(),cnt.end());
vector<int> all = a;
sort(all.begin() + 1,all.end());
map<int,vector<int>> mp;
for(int i = 1;i <= N;i ++) mp[all[i]].push_back(all[(i - 1 + mx) % N + 1]);
for(int i = 1;i <= N;i ++) {
cout << mp[a[i]].back() << " \n"[i == N] ;
mp[a[i]].pop_back();
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}