Codeforces #859(div4)CDF题

文章提供了三道Codeforces平台的算法问题解决方案。问题C涉及避免在特定位置出现特定字符的遍历优化;问题D利用前缀和降低暴力求解的复杂度;问题F通过模拟小球运动解决网格路径问题,关键在于处理边界条件和方向变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem - C - Codeforces

强行进行遍历更改会超时,其实我们只需要检索一下不该出现某个字母i的位置是否出现了i。例如字母a在1号位置,那么2,4,6.......号位置就不能出现a。

#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<cmath>
using namespace std;
int t;
void solve()
{
    int n;
    string s;
    cin>>n;
    cin>>s;
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j+=2){
            if(s[i]==s[j]){
                cout<<"No"<<endl;
                return;
            }
        }
    }
    cout<<"Yes"<<endl;
    return;
}
int main()
{
    cin>>t;
    while(t--) solve();
    return 0;
}

Problem - D - Codeforces

暴力解决的复杂度是n*q,明显有点大了,(暴力之前第一件事就是看数据大小!!!什么题都直接暴力只会白扣50昏)

区间内进行变动,很容易想到前缀和

#include<iostream>
#include<algorithm>
#include<string.h>
#include<cmath>
using namespace std;
int t;
void solve()
{
    int n,q;
    cin>>n>>q;
    int a[n+2];
    int sum[n+2];
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(i==1) sum[i]=a[i];
        else sum[i]=sum[i-1]+a[i];
    }
    while(q--){
        int l,r,k;
        cin>>l>>r>>k;
        int s=sum[l-1]+sum[n]-sum[r]+(r-l+1)*k;//前缀和把复杂度降到O(1)
        //cout<<s<<endl;
        if(s%2) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}
int main()
{
    cin>>t;
    while(t--) solve();
    return 0;
}

PS:一定要记得把测试数据删除干净


Problem - F - Codeforces

重点题

由于有四种方向,代表四个不同的状态,一共有n*m个格子,所以一共有4*n*m个不同的状态,我们使用一个三维数组表示小球目前所在位置的状态:vis[x][y][d],x,y表示坐标,d表示方向。

之后模拟小球的运动,while循环,直到到达目标位置或者出现相同状态时退出循环。

模拟小球运动的最关键点是小球的方向问题,一共有四个方向,而且是右上右下左上左下这样的对角线方向,题解中提供了一个非常厉害而且通用的表示方向的方法:d由0,1,2,3四个数字组成,分别表示四个方向:DL、UL、DR、UR,发现:有D的即方向向下的 %2==0,反之!=0;有L的<2,反之>=2

而且我们知道:碰撞到左右两边的时候,上下的方向是不改变的;碰撞到上下两边的时候,左右的方向是不改变的;

接下来就是简单的模拟一遍,由于数据不是很大,模拟一边不会超时。

#include <bits/stdc++.h>

using namespace std;
int t;
void solve()
{
    int n,m,x1,y1,x2,y2;
    string s;
    cin>>n>>m>>x1>>y1>>x2>>y2;
    x1--;y1--;x2--;y2--;
    cin>>s;
    int d=(s[0]=='U'? 1+(s[1]=='R'? 2 : 0) : 0+(s[1]=='R'? 2 : 0));//d表示方向
    bool vis[n][m][4];
    memset(vis,false,sizeof(vis));
    int x=x1,y=y1;
    int ans=0;
    while(!vis[x][y][d])
    {
        //cout<<"x="<<x<<" y="<<y<<" d="<<d<<endl;
        if(x==x2&&y==y2){
            cout<<ans<<endl;
            return;
        }
        int tb=0;//暂时记录反弹次数
        //讨论碰撞边界情况
        if(x==0&&d%2==1){
            d--;
            tb++;
        }
        if(x==n-1&&d%2==0){
            d++;
            tb++;
        }
        //到达上下的边界时 改变的是U和D R和L的属性并不改变
        if(y==0&&d<2){
            d+=2;
            tb++;
        }
        if(y==m-1&&d>=2){
            d-=2;
            tb++;
        }
        ans+=min(1,tb);//每次最多反弹一次
        //tb=2时表示走到四个顶点了进行反弹
        if(vis[x][y][d]) break;
        vis[x][y][d]=true;
        if(d>=2) y++;
        else y--;
        if(d%2==1) x--;
        else x++;
    }
    cout<<-1<<endl;
}

int main()
{
    cin>>t;
    while(t--) solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Awars_zpp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值