Codeforces Round 987 (Div. 2) A/B/C/D/E
A. Penchick and Modern Monument
题目链接:https://mirror.codeforces.com/contest/2031/problem/A
思路:
分析发现答案就是:\(总个数 - 最长上升子序列的个数\)
时间复杂度: \(O(n)\)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
void solve(){
cin>>n;
vector<int> h(n);
for(auto &hh:h)cin>>hh;
int mx=0;
vector<int> f(n);
for(int i=0;i<n;i++){
f[i]=1;
if(i){
for(int j=0;j<i;j++){
if(h[j]<=h[i])f[i]=max(f[j]+1,f[i]);
}
}
mx=max(mx,f[i]);
}
cout<<n-mx<<endl;
}
int main() {
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
}
B. Penchick and Satay Sticks
题目链接:https://mirror.codeforces.com/contest/2031/problem/B
思路:
因为只有相差为 \(1\) 的两个数才能进行互换,所以若不能进行排序,那么存在一个间隔,有 \(间隔前的最大值 - 间隔后的最小值 > 1\) 。所以可以预处理前缀最大和后缀最小在对应索引的值,并借此判断。
时间复杂度: O(n)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
void solve(){
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
vector<int> suf(n+1);
suf[n]=a[n];
for(int i=n-1;i;i--){
suf[i]=min(suf[i+1],a[i]);
}
int mx=a[1];
for(int i=2;i<=n;i++){
if(mx-suf[i]>1){
cout<<"No\n";
return;
}
mx=max(mx,a[i]);
}
cout<<"Yes\n";
}
int main() {
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
}
C. Penchick and BBQ Buns
原题链接:https://mirror.codeforces.com/contest/2031/problem/C
思路:
思维题。对于偶数序列来说一定可以,而奇数序列则不一定。若存在某个数出现了奇数次,不妨为 \(3\),那么这三个数之间的距离满足: $ a^2 + b^2 = c^2 $,那么显然最小的满足要求的距离为 \(a=9\) $ b=16$ \(c=25\),
对于长度为 \(27\) 的序列可以构造:1 3 3 4 4 5 5 6 6 1 2 7 7 8 8 9 9 10 10 11 11 12 12 13 13 1 2,那么大于 \(27\) 的序列也可进行构造。
所以,仅有长度小于 \(27\) 的且长度为奇数的序列无法构造。
时间复杂度:O(n)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
void solve(){
cin>>n;
if(n&1){
if(n<27){
cout<<-1<<endl;
}else{
vector<int> ans(n+1,0);
ans[1]=1,ans[10]=1,ans[11]=2,ans[26]=1,ans[27]=2;
for(int i=1,j=3;i<=n;i++){
if(ans[i]) cout<<ans[i]<<' ';
else{
cout<<j<<' '<<j++<<' ';
i++;
}
}
}
}else{
for(int i=1,j=1;i<=n;i+=2,j++){
cout<<j<<' '<<j<<' ';
}
cout<<endl;
}
}
int main() {
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
}
D. Penchick and Desert Rabbit
原题链接: https://mirror.codeforces.com/contest/2031/problem/D
思路:
兔子可以从当前位置跳到前缀中高于当前的位置,也可以从当前位置跳到后缀低于当前的位置。因为要找到每个位置可达的最高位置,开始考虑对通过题意进行构图,但发现递减序列的边的空间复杂度为 \(O(n^2)\),显然无法建图暴力搜索得到答案。
考虑对问题进行转化,转化为区间问题,通过区间合并+并查集对问题进行解决
转化过程:遍历整个序列每次遇到一个高于前缀最高的位置,我们就建立一个集合,直到下一个这种位置之前,显然每个集合的第一个位置是最高的位置,且集合内的各个位置可以通过这个位置相互转化,并且每个集合都存在一个最高点和最低点。最终从左到右,每个集合的最高点依次递增,但最低点并不确定。若两个集合间的位置可以相互转化,那么两个集合对应的最高最低区间一定有至少两个交点。所以便可对区间进行排序,然后区间合并,将较小最高的集合链接到较高的集合,这个操作可以通过并查集进行实现。
时间复杂度 O(n)
代码
// 转化为区间问题了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
struct Range{
int id;
int low,up;
bool operator<(const Range& t)const{ return low<t.low; }
};
int find(vector<int> &p,int x){
if(p[x]!=x)return p[x]=find(p,p[x]);
return x;
}
void solve(){
cin>>n;
vector<int> h(n+5);
for(int i=1;i<=n;i++) cin>>h[i];
int idx=0,maxp=0,low;
vector<Range> range;
vector<int> id(n+5),mh(n+5);
for(int i=1;i<=n;i++){
if(h[i]>h[maxp]){ // 如果大于就新建一个区间
if(maxp) range.push_back({idx,low,h[maxp]});
maxp=i;
low=h[i];
mh[++idx]=h[i];
}else low=min(low,h[i]); // 更新最小
id[i]=idx; // 节点i所属区间编号
}
range.push_back({idx,low,h[maxp]});
// 按最低点排序
sort(range.begin(),range.end());
vector<int> p(idx+1);
for(int i=1;i<=idx;i++)p[i]=i;
// 区间合并 利用并查集 将较小maxh值的合并到较大的上
int ed=-1,now=-1;
for(auto [x,lo,up]:range){
if(ed<=lo) ed=up,now=x;
else{
if(up>ed){
swap(x,now);
ed=up;
}
p[x]=now;
}
}
for(int i=1;i<=n;i++){
cout<<mh[find(p,id[i])]<<' ';
}
cout<<endl;
}
int main() {
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
}
E. Penchick and Chloe's Trees
原题链接: https://mirror.codeforces.com/contest/2031/problem/E
思路:
这题实际上就是把给的图转化为二叉树,然后看最小可能深度是多少。所以对于节点儿子大于两个的位置需要进行转化,使其深度尽可能小,发现类似于哈夫曼树,所以直接 \(DFS\) + 哈夫曼。
时间复杂度 O(nlogc)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+10;
int n;
vector<vector<int>> e;
inline void add(int a,int b){
e[a].push_back(b);
}
int dfs(int x,int father){
priority_queue<int,vector<int>,greater<int>> heap;
for(auto y:e[x]){
if(y==father)continue;
int s=dfs(y,x);
heap.push(s);
}
if(heap.empty()) return 1;
while(heap.size()>2){
auto p1=heap.top(); heap.pop();
auto p2=heap.top(); heap.pop();
heap.push(p2+1);
}
int mx=0;
while(!heap.empty()){
mx=heap.top();
heap.pop();
}
return mx+1;
}
void solve(){
cin>>n;
e=vector<vector<int>>(n+1);
int a;
for(int b=2;b<=n;b++){
cin>>a;
add(a,b),add(b,a);
}
int ans=dfs(1,-1);
cout<<ans-1<<endl;
}
int main() {
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
}

浙公网安备 33010602011771号