前言
浅浅放一张过年的雪景图(咦,有点马赛克好像,算了就这样吧)
上两次没出题解是上一段比较忙,然后那两场恰好也打的稀碎,所以直接开摆下机了,绝不是因为上一段沉迷王者荣耀和帕鲁。虽然这次的div3也是稀碎,但是确实是因为我自己对时间概念有点模糊,我想着5s随便写n^2来着,甚至wa的时候从来没想过是因为找位置的n^2的,我在写的时候还在想这个可以用O(n)来写,cf数据范围基本上不在5000以内都别想n^2的实现,吃一堑长一智吧,最难绷的还是赛后3分钟秒E,赛后破防日记。不过确实题目出的很好。codeforces的分数虽然掉了,但是回去也是蛮快的,慢慢提升就行,适当的掉分有利于勉励自己上班(Maybe)。
这一段补一些高级数据结构的基础吧,今天下午忙着牛客导致题解慢了点。
A. Make it White
其实翻译过来就是找到最左边的黑色和最右边的黑色的位置,作差后加一就是线段长度。很简单的题意,代码怎么写都ok的,赛时进不去卡麻了有点着急写的比较丑。
void solve() {
int n;
cin >> n;
string s;
cin >> s;
int l = 0,res = 0;
int flag=0;
for(int i = 0 ;i < n ;i ++)
{
if(s[i] == 'B' && flag == 0)
{
l = i;
flag=1;
}
if(s[i] == 'B')
res = max(res,i-l+1);
}
cout << res << endl;
}
B. Following the String
其实我感觉c是要比b难想的,但是我看很多同学都是先做的C在做的b,有点诧异。
这个b题就是相当于每个字母都有对应的出现顺序,我们要做的就是还原顺序,就是许多个排列从前往后打乱顺序,那我们可以想到采取map来进行存储,每次遍历26个小写字母,用26个字母去存储26个序列,当遇到对应位置将对应元素放入字符串后加一结束遍历即可。
void solve() {
int n;
cin >> n;
map<char,int>ma;
for(char i = 'a' ;i <= 'z' ;i ++)
ma[i]=0;
string s="";
for(int i = 0 ;i < n ;i ++)
{
int x;
cin >> x;
for(char j = 'a' ;j <= 'z';j ++)
{
if(ma[j] == x)
{
s.push_back(j);
ma[j]++;
break;
}
}
}
cout << s << endl;
}
C. Choose the Different Ones!
这个题我们可以注意到其实是很巧妙的一道题,从a和b两个数组中来取元素,每个数组都拿k/2个元素,并且能恰好构成K的一个排列。那么我们想到可以满足的条件,首先每个数组中要有至少k/2个不同的1~k间的元素,其次这些元素放在一起要正好能组合出一个1~k的排列。有想不明白的同学可以考虑自己任意设置情况,去找一下反面情况。因为只要元素数量大于等于k/2并且能能全部出现排列,总有一种选择方式能使得全部出现。
void solve() {
int n,m,k;
cin >> n >> m >> k;
set<int>s1,s2,s;
s1.clear();s.clear();s2.clear();
int ans1=0,ans2=0;
for(int i = 0 ;i < n ;i ++)
{
int x;
cin >> x;
if(x <= k)
{
s1.insert(x);
s.insert(x);
}
}
for(int i = 0 ;i < m ;i ++)
{
int x;
cin >> x;
if(x <= k)
{
s2.insert(x);
s.insert(x);
}
}
if(s.size() == k && s1.size() >= k / 2 && s2.size() >= k/2)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
D. Find the Different Ones!
题意很简单,只要找到这段区域内元素是否有两个不同的,如果有就将他们的位置输出,没有的话就输出两个-1。此时,一个迫不及待小伙子看到5s开心的写起了暴力。对于每一个区间,我们可以想到,如果我们可以维护每一个点距离他最左和最右的不同的点的位置,那么我们每次查询,则只需要访问其左端点的右端最近不同点和右端点的左端最近的不同点即可满足题意。那么我们预处理一个l,r数组处理每个结点最左和最右不同结点,我们可以想到,对于每一个顶点,如果其和左边的值相等,则其最近左边不同点应该就和左边值相等,和左边值不相等的话最近不同点就应该是左边值的下标。右端点也同理。真是一场酣畅淋漓的暴力呀!
void solve() {
int n;
cin >> n;
vector<int>v(n);
for(int i = 0 ;i < n ;i ++)
{
cin >> v[i];
}
vector<int>r(n,-1);
vector<int>l(n,-1);
for(int i = 0 ;i < n ;i ++)
{
if(v[i] == v[i-1]) l[i] = l[i-1];
else l[i] = i-1;
}
for(int i = n-2 ;i >= 0 ;i --)
{
if(v[i] == v[i+1]) r[i] = r[i+1];
else r[i] = i+1;
}
int ans = 1;
int m; cin >> m;
while(m--)
{
int x,y;
cin >> x >> y;
x--;y--;
if(r[x]>=x && r[x] <= y)
{
cout << x + 1 << " " << r[x] + 1<< endl;
continue;
}
if(l[y] >= x && l[y] <= y)
{
cout << l[y] + 1 << " " << y + 1<< endl;
continue;
}
cout << -1 << " " << -1 << endl;
}
}
E. Klever Permutation
E还是比较遗憾的,感觉很符合我的做题胃口,可惜赛时没留时间。
翻译成白话文大概就是从1~n-k的每个下标i开始,每k个元素的和差值不能超过1。首先我们观察样例可以发现,从第k+1个元素开始,此时每个元素要么是前k个元素加一或者减一来维持动态平衡,那我们可以想一下这个过程,其实就是一位加一位减的过程,为了能满足这个过程,我们需要在前两位上首先 确定最大值和最小值,即n,1,那我们不难想出对于第一个位置来讲,我们会首先减一一直到结束,那么我们会发现其实就是(n/k),如果余数n%k大于所处的位置的话,就说明n开始的元素要每次-1不至于n/k,到余数的范围内仍需要减一,而第二个位置1每次加的值也是至少加n/k,随后根据余数位置来判断出是否需要加一,我们确定的范围即为(n/k)+1或者(n/k),随后第三个位置就是 n - 我们确定的范围,第四个位置就是1+我们确定的位置。看代码结合文字应该会更好理解一点。
void solve() {
int n,m;
cin >> n >> m;
int mx=n,mi=1;
int k = n / m;
vector<int>v;
int q = n%m;
for(int i = 0 ;i < m / 2;i++)
{
v.push_back(mx);mx-=k; if(i * 2 < q) mx--;
v.push_back(mi);mi+=k; if(i * 2 + 1 < q) mi++;
}
for(int i = 0;i<n-m;i++)
{
if(v[i] >= n / 2) v.push_back(v[i]-1);
else v.push_back(v[i]+1);
}
for(auto i : v)
cout << i << " ";
cout << endl;
}
F. Microcycle
这次的F虽然过的人很少,但是其实难度并不高,题意告诉需要找到最小边权所在的环,随后输出这条环的路径即可。首先我们会想到要找到一个环上的最小边,我们首先需要找到一个环,环的话就采取并查集来实现即可,若是两个节点的头节点相同,说明这两个点位于同一个环上,那么如如何找到权值最小的环上边呢,那我们可以想到,若是将结点按照从大到小排序,先建图,随后在遍历过程中若是他们两个结点能构成一个环,此时说明就差最小边即可构成环,此时我们在最小边的两个节点间通过dfs求出路径上的点即可。
/**
* author: Huan
* created: 2023-02-07 10:52:00
* 再强一点点就好了(>﹏<)
**/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5+10;
int fa[maxn];
int find(int x)
{
return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
int merge(int u,int v)
{
u = find(u);
v = find(v);
if(u == v) return 1;
fa[u] = v; return 0;
}
typedef struct
{
int x,y,w;
}node;
int n,m;
vector<vector<int>>v;
vector<int>vis(maxn),ans;
void dfs(int u ,int r)
{
vis[u]=1;
ans.push_back(u);
if(u == r)
{
cout<< ans.size() << endl;
//cout << "5418888888" << endl;
for(auto i : ans)
cout << i << " ";
cout << endl;
return;
}
for(auto i : v[u])
{
if(!vis[i])
{
dfs(i,r);
}
}
ans.pop_back();
}
void solve() {
cin >> n >> m;
v.resize(n+1);
ans.clear();
for(int i = 1 ;i <= n ;i ++)
{
fa[i] = i;
vis[i] = 0;
v[i].clear();
}
vector<node>a(m);
for(int i = 0 ;i < m ;i ++)
{
int x,y,z;
cin >> x >> y >> z;
a[i]={x,y,z};
}
sort(a.begin(),a.end(),[&](node x,node y)
{
return x.w>y.w;
});
int mi,id;
for(int i = 0 ;i < m ;i ++)
{
if(merge(a[i].x,a[i].y))
{
mi = a[i].w;
id = i;
}
}
for(int i = 0 ;i < m ;i ++)
{
if(id != i)
{
v[a[i].x].push_back(a[i].y);
v[a[i].y].push_back(a[i].x);
}
}
cout << mi << " ";
dfs(a[id].x,a[id].y);
}
signed main() {
std::ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int tt = 1; cin >> tt;
while (tt--) solve();
return 0;
}