CF-Round598总结

B:Minimize the Permutation
题意:
给出一段长度为n的序列,你可以对每一个位置与他后面一个数进行交换,每一个位置仅能交换一次。问可以得到的最小字典序序列是多少。
解题思路:
由于要求字典序最小,所以贪心的思路每一次肯定把最小的元素提到前面,对于已经移动过的区间,则不需要在进行移动了,只需要对接下来的区间找到最小值提到可以移动的区间最前面。递归即可。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=1e5+10;
int n,m,k,T;
int a[110];
void solve(int l,int r){
    if(l>=r)return;
    int ind=l,mi=a[l];
    for(int i=l;i<=r;i++)if(a[i]<mi){ind=i,mi=a[i];}//找到可以移动区间内的最小值
    for(int i=ind;i>l;i--)swap(a[i],a[i-1]);//把最小值移到区间开头
    if(ind!=l)solve(ind,r);//特判若最小值不是开头则最小值位置可以被移动
    else solve(ind+1,r);//否则最小值位置不可以被移动
}
int main() {
    cin>>T;
	while(T--){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        solve(1,n);
        for(int i=1;i<=n;i++)cout<<a[i]<<" ";cout<<endl;
	}
}

C: Platforms Jumping
题意:给出长度为n河流和m个木板和可以跳跃的距离d,你可以按顺序随意防止这些木板在河流上,判断是否可以通过木板从河流的一端到达另一端,并输出一个可行的方案。
解题思路:
首先按照贪心的思路来想,每次都跳越最大的距离d再加上木板可提供的距离若总距离小于n则不能到达,否则可以。对于方案,可以先使m块木板紧靠在一起放置在河流另一端,然后从河的这一端开始跳,若跳不到木板上,则将最外侧的木板移动到跳跃的位置下。直到跳到对岸。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=1e3+10;
int n,m,k,T,d,sum;
int a[N],ans[N];
int main() {
    cin>>n>>m>>d;
    for(int i=1;i<=m;i++){
        cin>>a[i];sum+=a[i];//sum记录木板总长度
    }
    if((m+1)*(d-1)+sum<n)cout<<"NO";//判断是否能到达
    else {
        cout<<"YES"<<endl;
        int now=1,t=1;//now记录当前位置,t记录第几块木板
        while(now<=n){
            if(n-now-d+2<sum){
                for(int i=1;i<=n-now+1-sum;i++)cout<<0<<" ",now++;
            }else {
                for(int i=1;i<=d-1;i++)cout<<0<<" ",now++;
            }
            for(int i=1;i<=a[t];i++)cout<<t<<" ",now++;
            t++;
            sum-=a[t-1];//每一次最外侧木板被移动
        }
    }
    return 0;
}

D:Binary String Minimizing
题意:
给出你一段长为n的二进制串和最多可以进行的操作数k,问经过n次操作后字典序最小的二进制串是什么。
思路:
同样贪心思维,字典序最小肯定将0都移动到经可能的前面,考虑每一次移动需要花费的移动次数,若可以移动到上一个0的下一个位置,则k减去当前操作次数即可,否则将当前0移动到当前位置-k的位置上。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=1e6+10;
int n,m,T,d,sum,t;
int ans[N];
ll k;
int v[N];
char s;
int main() {
    cin.sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n>>k;
        t=0;
        for(int i=0;i<n;i++){cin>>s;if(s=='0')v[t++]=i;ans[i]=1;}//记录每一个0的初始位置
        int last=-1;//last记录上一个0的位置
        for(int i=0;i<t;i++){
            if(k>=v[i]-last-1){//k大于可以执行的操作数
                k-=(v[i]-last-1);
                v[i]=last+1;//当前0的位置调整到上一个0的位置加1
                last=v[i];
            }else {
                v[i]-=k;break;//否则将该位置的0向前提k个即可
            }
        }
        for(int i=0;i<t;i++)ans[v[i]]=0;//对位置为0的点标记为0
        for(int i=0;i<n;i++){
            if(ans[i])cout<<1;
            else cout<<0;
        }cout<<endl;
    }
    return 0;
}

F:Equalizing Two Strings
题意:给出两个长度均为n的字符串,可选择长度为len的区间对两个字符串进行反转操作,问两个字符串能否变成一样。
解题思路:
首先若能变成一样,那么对两个字符串进行排序后对应位置的字符一个相等,其次对于任意区间为len的反转操作都可以变成为区间为2的反转操作进行若干次得到。所以若排序后字符串中有连续两个字符相等,并且对应位置字符相等的条件下,这肯定可以变成相同的。此外,两个字符串中的逆序对奇偶性要相同。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=1e6+10;
int n,m,T,d,sum,t;
string s1,s2,s3,s4;
ll check(string s){
    ll res=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<i;j++){
            if(s[i]>s[j])res++;
        }
    }
    return res;
}
void solve(){
    cin>>n>>s1>>s2;
    s3=s1;s4=s2;
    sort(s3.begin(),s3.end());//排序字符串
    sort(s4.begin(),s4.end());
    for(int i=0;i<n;i++){
        if(s3[i]!=s4[i]){cout<<"NO"<<endl;return;}//判断对应位置是否相等
    }
    for(int i=0;i<n-1;i++){//判断是否有连续字符相等
        if(s3[i]==s3[i+1]){cout<<"YES"<<endl;return;}
        if(s4[i]==s4[i+1]){cout<<"YES"<<endl;return;}
    }
    if(check(s1)%2==check(s2)%2)cout<<"YES"<<endl;//判断逆序对的奇偶性是否相等
    else cout<<"NO"<<endl;
    return ;
}
int main() {
    cin.sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值