好久没打cf了,,,这个假期太摆烂了呜呜呜,应该会掉大分
(不知道为啥没rated,也没给我发消息啊???)
似乎是手速场,可惜跟不上节奏了
A. Wonderful Permutation
给出一个permutation和一个k,每次交换可以使得任意两数互换,使得前k个数和最小的做少操作次数是多少。
思路:前k个数之和最小肯定是1加到k,map维护一下,仅交换不在这个范围内的即可。
AC Code:
#include<bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t,n,k;
int a[N];
std::map<int,int>mp;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n>>k;
mp.clear();
for(int i=1;i<=k;i++){
mp[i]++;
}
int ans=0;
for(int i=1;i<=n;i++){
std::cin>>a[i];
if(i<=k&&!mp[a[i]]) ans++;
}
std::cout<<ans<<'\n';
}
return 0;
}
B. Woeful Permutation
给出一个n,构造一个permutation,使得每个i和p[i]的最小公因数之和最大。
思路:首先某个数一定与相邻的数互质,满足这个条件可以使得最小公因数最大,那么最大化利用每个数的方法是交换相邻两数,注意奇数个数时首先从最后开始交换。
AC Code:
#include<bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t,n;
int ans[N];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n;
for(int i=1;i<=n;i++){
ans[i]=i;
}
if(n&1){
for(int i=2;i<=n;i+=2){
std::swap(ans[i],ans[i+1]);
}
}
else{
for(int i=1;i<=n;i+=2){
std::swap(ans[i],ans[i+1]);
}
}
for(int i=1;i<=n;i++){
std::cout<<ans[i]<<" \n"[i==n];
}
}
return 0;
}
os:假期躺平,后果就是B题还会WA两次
C. Sort Zero
给出一个数组a,每次操作可以选择一个数x并使数组中所有值为x的元素变成0,最少需要几次操作使得数组非递减排列。
思路:贪心即可。遇到递减的一对数,就把前面的都变为0,,注意标记前面变为0的数,后面不要重复操作了。
考虑贪心的可行性,只要有递减的一对数,想将其变成合法序列,必须前一个数变小,那只能是0,前面大于0的数也必须相应变为0,而后面等于该数的位置也会变成0,一系列也就只能全为0了。注意代码写法,map相互赋值是O(n)的。其实好像也不难想,,是我菜了
AC Code:
#include<bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t,n,ans;
int a[N];
std::map<int,int>mp;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n;
ans=0;
for(int i=1;i<=n;i++){
std::cin>>a[i];
}
mp.clear();
int pos=-1;
if(a[1]) mp[a[1]]=1;
for(int i=2;i<=n;i++){
if(a[i]<a[i-1]){
ans=mp.size();
pos=i;
}
if(ans<mp.size()&&mp[a[i]]&&mp[a[i]]<pos){
ans=mp.size();
}
if(!mp[a[i]]&&a[i]) mp[a[i]]=i;
}
std::cout<<ans<<'\n';
}
return 0;
}
os:还因为mapT了一发,寄
D. Empty Graph
给出一个数组a,有k次操作,每次操作可以令a数组中某个数变为x,n个点的无向图,l点到r点的距离是区间l到r在数组a中的最小值。问在图中最长边的值。
思路:学习大佬的思路首先有个结论是显然的,区间越长,最小值不会较大。这样要求最大的值,所以有三条路线是最优的:1、l->r;2、l->1->r(a数组中最小值在1~l中,且2*d[1,n]<d[l,r]);3、l->n->r(a数组中最小值在r~n中,且2*d[1,n]<d[l,r]),所以d[l,r]=min(d[1,n]*2,d[l,r]),答案就是min(d[1,n]*2,max(d[u,v]))。由于区间min的单调递减性,所以d[u,v]取最大的话,只要满足v=u+1就行了,也就是说只用判断相邻的是否满足条件就行了,考虑二分答案,注意最小值限制即可。
AC Code:
#include<bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t,n,k;
int a[N],b[N];
bool check(int x){
int nk=k;
for(int i=1;i<=n;i++){
if(a[i]*2<x){
b[i]=1e9;
nk--;
if(nk<0) return false;
}
else b[i]=a[i];
}
if(nk>=2) return true;
for(int i=2;i<=n;i++){
if(std::min(b[i],b[i-1])>=x) return true;
if(std::max(b[i],b[i-1])>=x&&nk>=1) return true;
}
return false;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n>>k;
for(int i=1;i<=n;i++){
std::cin>>a[i];
}
int l=1,r=1e9;
while(l<r){
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
std::cout<<l<<'\n';
}
return 0;
}