2024牛客寒假算法基础集训营4

文章讨论了几道编程题目,涉及柠檬可乐的简单模拟、左右互博的奇偶性判断、冬眠问题的暴力模拟、守恒原理的应用、漂亮数组的划分问题以及数三角形的前缀和方法。
摘要由CSDN通过智能技术生成

目录

A.柠檬可乐

B.左右互博

C.冬眠

D.守恒

E.漂亮数组

F.来点每日一题

G.数三角形(easy)


A.柠檬可乐

阅读理解题,依照题目直接模拟即可

void solve(){
   
    int a,b,k; cin>>a>>b>>k;
    if(a>=k*b) cout<<"good"<<endl;
    else cout<<"bad"<<endl;
    return ;
}

B.左右互博

简单博弈,我们要找到操作的本质是什么我们可以发现,n最后一定是变成n个1也就是说一定要进行n-1次操作,如果能理解到这里那就是判断奇偶了

void solve(){
   
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        ans+=(x-1)&1;
    }
    cout<<(ans&1 ? "gui" : "sweet")<<endl;
    return ;
}

C.冬眠

简单模拟,可以发现明显的数据范围很小的这件事情我们计算一下直接模拟所需要的时间,发现是可以通过的所以直接暴力模拟即可

void solve(){
   
    cin>>n>>m>>x>>y;
   
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>s[i][j];
    
    cin>>p>>q;
    for(int i=1;i<=q;i++){
        int op,x; cin>>op>>x;
        a[i]={op,x};
    }
    while(p--){
        for(int i=1;i<=q;i++){
            auto [op,x]=a[i];
            if(op==1){
                char y=s[x][m];
                for(int i=m;i>1;i--)
                    s[x][i]=s[x][i-1];
                s[x][1]=y;
            }
            else{
                char y=s[n][x];
                for(int i=n;i>1;i--)
                    s[i][x]=s[i-1][x];
                s[1][x]=y;
            }
        }
    }
    cout<<s[x][y]<<endl;
    return ;
}

D.守恒

简单思维,我们可以发现又是典型的加一减一操作那么总和一定是不变的,由于操作次数不限制,那么这个数组可以随意变化,要找的是最大公约数只要sum%x==0都是可以做到的

如下

x,x,x....sum-(n-1)*x

特列:不过同时注意满足这个要求至少需要两位如果是一位的话答案就是固定的一了


void solve(){
   
    cin>>n;
    LL sum=0;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        sum+=x;
    }
    if(n==1){
        cout<<1<<endl;
        return ;
    }
    int ans=0;
    for(LL i=1;i*n<=sum;i++){
        if(sum%i==0){
             ans++;
        }
    }
    cout<<ans<<endl;
    
    return ;
}

E.漂亮数组

数组划分问题,我们要求的是k倍数的数组,那么直接从前面开始即可,一直统计前面出现的余数的出现,如果说加上后面这个数出现了前面出现过的数,或者说现在满足的那就是取到当前这个位置即可,一般的划分问题都是这样

void solve(){
    
    cin>>n>>m;
    map<LL,int> mp;
    LL ans=0,res=0;
    for(int i=1;i<=n;i++){
        LL x; cin>>x;
        x%=m;
        ans=(ans+x)%m;
        if(mp.count(ans) || ans==0){
            ans=0;
            res++;
            mp.clear();
        }
        else mp[ans]++;
    }
    cout<<res<<endl;
    return ;
}

F.来点每日一题

考虑到n的数据范围以及题目的要求我们不难想到这是一个动态规划问题,但是如何定义状态是个问题,我们发现当前为最小值不一定是被放弃的解,所以同时维护最小值和最大值,接着考虑如果定义整个状态可以想到dp[l][r][k][2]表示从l,r中选k个数当前的最大和最小值注意一些没有状态的舍去,所以我们再定义一个d[r]表示以r结尾的最大值即可

LL dp[M][M][7][2];
LL a[M];
LL d[M];
void solve(){
   
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)
            for(int k=0;k<=6;k++){
                dp[i][j][k][0]=1e18,dp[i][j][k][1]=-1e18;
            }
    
    for(int L=1;L<=n;L++){
        for(int R=L;R<=n;R++){
            dp[L][R][1][0]=min(dp[L][R-1][1][0],a[R]);
            dp[L][R][1][1]=max(dp[L][R-1][1][1],a[R]);
            
            for(int k=2;k<=6;k++){
                if(R-L+1<k) break;
                if(k%2==0){
                    dp[L][R][k][0]=min(dp[L][R-1][k-1][0]-a[R],dp[L][R-1][k][0]);
                    dp[L][R][k][1]=max(dp[L][R-1][k-1][1]-a[R],dp[L][R-1][k][1]);
                }
                else{
                    dp[L][R][k][0]=min({dp[L][R-1][k-1][0]*a[R],dp[L][R-1][k][0],dp[L][R-1][k-1][1]*a[R]});
                    dp[L][R][k][1]=max({dp[L][R-1][k-1][1]*a[R],dp[L][R-1][k][1],dp[L][R-1][k-1][0]*a[R]});
                }
            }
        }
    }
    for(int R=1;R<=n;R++)
        for(int L=0;L<R;L++)
           if(R-L+1<=6) d[R]=max(d[R],d[L]);
           else d[R]=max(d[R],d[L]+dp[L+1][R][6][1]);
    cout<<d[n]<<endl;
    return ;
}

G.数三角形(easy)

简单性质,首先理清楚题目意思什么样是符合要求的三角形,然后观察数据范围我们发现最下面的一行我们可以考虑使用前缀和维护,边的长度可以考虑暴力维护不会超时即可通过

void solve(){
   
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            cin>>s[i][j];
            h[i][j]=h[i][j-1];
            if(s[i][j]=='*') h[i][j]++;
        } 
    
    int ans=0;
    auto bfs = [&](int x,int y){
        for(int i=1;i<=max(n,m);i++){
            if(x+i>n || y-i<1 || y-i>m) break;
            if(s[x+i][y-i]!='*' || s[x+i][y+i]!='*') break;
            if(h[x+i][y+i]-h[x+i][y-i-1]==2*i+1){
                 ans++;
            }
        }
        return ;
    };
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(s[i][j]=='*') bfs(i,j);
    cout<<ans<<endl;
    return ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值