CF-Round605比赛总结

Codeforces Round #605 (Div. 3)

A: Three Friends
题意:
给出三个点的坐标,每一个点可以进行左移或者右移单位1,或者不移动,问最后三个点之间的相对距离最小值是多少。
解题思路:
因为每一个点最多三种情况,所以枚举一下即可。
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m,k,t;
ll a,b,c,d;
ll num[3]={0,1,-1};
void solve(){
    ll ans=((ll)1<<40);
    cin>>a>>b>>c;
    for(int i=0;i<3;i++){
        ll a1=a+num[i];
        for(int j=0;j<3;j++){
            ll b1=b+num[j];
            for(int p=0;p<3;p++){
                ll c1=c+num[p];
                ans=min(ans,abs(a1-b1)+abs(a1-c1)+abs(c1-b1));
            }
        }
    }
    cout<<ans<<endl;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B:Snow Walking Robot
题意:
给出一段机器指令,你可以删去一些指令,使最后剩余的指令操作之后回到原点,且这个过程中不能经过相同点,问最多可以剩下多少指令。
解题思路:
分析可知,要回到原点,所以向上的操作次数等于向下的操作次数,向左的操作次数等于向右的操作次数,这个地方可以统计取min,对于可行的操作方案,只需要用剩余的操作按照左上右下画一个正方形即可。还需要注意一点,当向左向右的操作次数为0时,向上和向下只能为1,反之亦然。
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m,k,t;
int a,b,c,d,e,f;
string s;
void solve(){
    a=b=c=d=0;
    cin>>s;
    int len=s.size();
    for(int i=0;i<len;i++){
        if(s[i]=='L')a++;
        else if(s[i]=='R')b++;
        else if(s[i]=='U')c++;
        else if(s[i]=='D')d++;
    }
    e=min(a,b);
    f=min(c,d);
    if((e==0&&f>1)||(e>1&&f==0)){e=min(1,e);f=min(1,f);}
    cout<<(e+f)*2<<endl;
    for(int i=0;i<e;i++)cout<<"L";
    for(int i=0;i<f;i++)cout<<"U";
    for(int i=0;i<e;i++)cout<<"R";
    for(int i=0;i<f;i++)cout<<"D";
    cout<<endl;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

C:Yet Another Broken Keyboard
题意:
给出一段字符串,其中一些字符你打不出来,为其他字符你可以打出来的子串个数最多为多少。
解题思路:
可以统计连续的可以打出的字符的长度,假设为n那么此段区间的答案贡献是n*(n+1)/2,累加一下即可。
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n,m,k,t;
int vis[27];
char c;
string s;
void solve(){
    cin>>n>>m;
    cin>>s;
    ll ans=0;
    for(int i=1;i<=m;i++)cin>>c,vis[c-96]=1;
    vector<int>v;
    v.push_back(-1);
    for(int i=0;i<n;i++)if(!vis[s[i]-96])v.push_back(i);
    v.push_back(n);
    for(int i=1;i<v.size();i++){
        ans+=(ll)(v[i]-v[i-1]-1)*(v[i]-v[i-1])/2;//相邻差就是可以打出的字母区间长度
    }
    cout<<ans<<endl;
}
int main(){
    solve();
    return 0;
}

D:Remove One Element
题意:
给出一段正整数序列,你可以选择移除一个,问序列中最长严格递增子段长度是多少。
解题思路:
可以用dp方程进行转移,dp[i][0]代表以i为结尾不采用移除的最长子段,dp[i][1]代表采用移除可以达到的最大字段。
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n,m,k,t;
int a[N],dp[N][2];
void solve(){
    int ans=1;
    dp[1][0]=1,dp[1][1]=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=2;i<=n;i++){
        if(a[i]>a[i-1]){
            dp[i][0]=dp[i-1][0]+1;
            if(a[i]>a[i-2]&&i>2)dp[i][1]=max(dp[i-1][1],dp[i-2][0])+1;//如果大于前前一项则可以采用移除前一项和不移动取max
            else dp[i][1]=dp[i-1][1]+1;
        }else {
            if(a[i]>a[i-2]&&i>2)dp[i][1]=dp[i-2][0]+1,dp[i][0]=1;
            else dp[i][0]=1,dp[i][1]=1;
        }
        ans=max(ans,max(dp[i][0],dp[i][1]));
    }
    printf("%d\n",ans);
}
int main(){
    solve();
    return 0;
}

E:Nearest Opposite Parity
题意:
给出一段整数序列,你可以在第i个位置向左或者向右移动a[i]个单元格,如果不越界,问在第i个位置移动到与它奇偶性不同的单元格的最小步数为多少。
解题思路:
这道题理解的还不是很理解,解题过程是先把能到达的两个点反向建一条边,如果这两个点奇偶性不同,则将当前点加入到队列中,再用这个点来更新奇偶性相同的点。
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n,m,k,t;
int a[N],ans[N],vis[N];
vector<int>v[N];
queue<int>q;
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),ans[i]=1e9;
    for(int i=1;i<=n;i++){
        int now=i-a[i];
        if(now>=1){
            v[now].push_back(i);//反向健边
            if(a[now]%2!=a[i]%2){
                ans[i]=1;
                if(!vis[i])q.push(i);//将一步就可以到达且奇偶性不同的加到队列中
                vis[i]=1;
            }
        }
        now=i+a[i];
        if(now<=n){
            v[now].push_back(i);
            if(a[now]%2!=a[i]%2){
                ans[i]=1;
                if(!vis[i])q.push(i);
                vis[i]=1;
            }
        }
    }
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int nxt:v[now]){//更新可以到达点的最短距离
            if(!vis[nxt]&&a[nxt]%2==a[now]%2&&ans[now]+1<ans[nxt]){
                vis[nxt]=1;
                ans[nxt]=ans[now]+1;
                q.push(nxt);
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(ans[i]==1e9)printf("-1 ");
        else printf("%d ",ans[i]);
    }
}
int main(){
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值