Codeforces Round 1031 (Div. 2) A~D

A

solution

一眼贪心,先尽量多的制作两种烧烤消耗温度较少的一种,然后再检验剩下的温度是否能制作另一种。

code

查看我の代码
#include<bits/stdc++.h>
using namespace std;
int T,k,a,b,x,y;
int ans;
signed main(){
    cin>>T;
    while(T--){
        cin>>k>>a>>b>>x>>y;
        ans=0;
        if(x>y){
            swap(a,b);
            swap(x,y);
        }
        if(k>=a){
            int tt=((k-a)/x)+1;
            ans+=tt;
            k-=tt*x;
        }
        if(k>=b){
            int tt=((k-b)/y)+1;
            ans+=tt;
            k-=tt*y;
        }
        cout<<ans<<endl;
    }
    return 0;
}

B

solution

这个题没有限制必须放在给定区间内,只需要全覆盖就可以。无非就两种情况,全部横着对齐和全部竖着对齐。判断一下纵坐标差或横坐标差是否能整除填充物块的横竖长度即可。

需要注意给定两物块边界差可能是负数,需要特殊判断

code

查看我の代码
#include<bits/stdc++.h>
using namespace std;
int T,w,h,a,b;
signed main(){
    cin>>T;
    while(T--){
        cin>>w>>h>>a>>b;
        int xt1,yt1,xt2,yt2;
        cin>>xt1>>yt1>>xt2>>yt2;
        int xt,yt;
        if(xt1>xt2) swap(xt1,xt2);
        if(yt1>yt2) swap(yt1,yt2);
        xt1+=a;yt1+=b;
        xt=xt2-xt1;yt=yt2-yt1;
        if(xt<0) xt=-1;
        if(yt<0) yt=-1;
        if((xt%a==0&&xt!=-1)||(yt%b==0&&yt!=-1)) puts("Yes");
        else puts("No");
    }
    return 0;
}

C

solution

自习思考会发现一旦在一个空点炸了之后就可以不断往外一点一点扩张,也就说 \(得到的金子=总金子-第一次炸没的金子\)

二维前缀和,贪心找第一次炸没最少的点即可。注意炸弹可以炸边界外,判断负数

code

查看我の代码
#include<bits/stdc++.h>
using namespace std;
const int N=507;
int T,n,m,k;
int mp[N][N],mpt[N][N];
string st;
int xt(int x,int y,int i,int j){
    if(x<=0) x=1;
    if(y<=0) y=1;
    if(i>n) i=n;
    if(j>m) j=m;
    return mpt[i][j]-mpt[x-1][j]-mpt[i][y-1]+mpt[x-1][y-1];
}
signed main(){
    cin>>T;
    while(T--){
        cin>>n>>m>>k;
        k--;
        for(int i=1;i<=n;++i){
            cin>>st;
            for(int j=1;j<=m;++j){
                mpt[i][j]=0;
                if(st[j-1]=='.') mp[i][j]=mpt[i][j]=0;
                else if(st[j-1]=='#') mp[i][j]=-1;
                else mp[i][j]=mpt[i][j]=1;
                mpt[i][j]+=(mpt[i][j-1]+mpt[i-1][j]-mpt[i-1][j-1]);
            }
        }
        int ans=mpt[n][m];
        int minn=ans;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(mp[i][j]==0&&xt(i-k,j-k,i+k,j+k)<minn){
                    minn=xt(i-k,j-k,i+k,j+k);
                }
            }
        }
        cout<<ans-minn<<endl;
    }
    return 0;
}

D

solution

伪难题,洛谷给评了蓝题

实际上思路很简单,按照规则输的牌不消除,所以可以用自己比对方大的一些牌反复鞭尸对方一张弱的牌取胜,显然如果答案为\(k\)成立,我们一定可以通过至多一次的操作将自己牌中前k个数的最小值大于对方前n-k+1个数的最小值。 (为什么是n-k+1而不是n-k呢,因为对方就算n-k全赢了我们也可以鞭尸第n-k+1个) 直接暴力枚举答案判断即可。

注意记录最小值的同时还要记录次小值,进行一次操作后前k个数的最小值可能会变为了原来的次小值

code

查看我の代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int T,n,a[N],b[N],minn1[N],min1t[N],maxk[N],minn2[N];
int visa[2*N],visb[2*N];
signed main(){
    cin>>T;
    while(T--){
        cin>>n;
        minn1[0]=2*N;
        min1t[0]=2*N;
        for(int i=1;i<=n;++i){
            cin>>a[i];
            if(minn1[i-1]>a[i]){
                minn1[i]=a[i];
                min1t[i]=minn1[i-1];
            }else{
                minn1[i]=minn1[i-1];
                min1t[i]=min(min1t[i-1],a[i]);
            }
        }
        maxk[n+1]=0;
        for(int i=n;i>0;--i){
            maxk[i]=max(maxk[i+1],a[i]);
        }
        minn2[0]=2*N;
        for(int j=1;j<=n;++j){
            cin>>b[j];
            minn2[j]=min(minn2[j-1],b[j]);
        }
        int ans=0;
        for(int i=1;i<n;++i){
            if((minn1[i]>minn2[n-i+1]||maxk[i+1]>minn2[n-i+1])&&min1t[i]>minn2[n-i+1]){
                ans=i;
            }
        }
        if(minn1[n]>b[1]) ans=n;
        cout<<ans<<endl;
    }
    return 0;
}

posted @ 2025-06-21 12:07  SZBR_yzh  阅读(108)  评论(0)    收藏  举报