CODEFORCE DIV2 NO.996(好社畜的场次名)

这一次的博客其实早就应该发布了,但是当时急着回家睡觉,于是就直接把博客的编辑页面给关闭了,于是没有保存,完成了3/4的博客就这样没有了,对,所以这件事启示了我们写完博客一定要保存好草稿,不然就是唐完了。

问就是唐龙

首先是这场比赛的评价,当时真的是犯蠢了,感觉是学数据结构学魔怔了,尽想着怎么用普通的数据结构去解决问题,而不是去想着用一些有用的贪心方法来解决问题,这也就导致了整场比赛制作出了一道题,非常大的失误,所以其实这篇博客也可以算是一个对于包含了贪心思想的题目的阅读,算是,然后主要会集中于前面4个题目,后面的题目没有时间补了。所以就这样了。下面是比赛的链接。
https://codeforces.com/contest/2055/problem/C(这里是C题的,自己调一下吧)

首先是第一道题,这一个题就是一个数学的猜想题,比较简单,可以算作是一个最基础的博弈论,首先就是两只青蛙,他们若是想要去赢得比赛,那么他们就需要去先让对方去走,当他们之间距离满足r-l=1时,这时如果再去让比赛,那么接下来,由于不可以站在同一片荷叶上的时候,那么到了当前轮次的青蛙只可以选择后退,然后直到退到无法退后为止,然后输掉比赛。在这里,其实后面再后退的流程不用再判断了,只要去判断当前是谁的回合就可以了,那么这样子就结束了整一个比赛。

下面是他的AC代码。

#include<bits/stdc++.h>
using namespace std;

int n;
int num,ap,bp;
void sol(){
    cin>>num>>ap>>bp;
    int tot=0;
    if (ap<bp){
        while(true){
        if(tot%2==0){
            ap++;
        }
        else{
            bp--;
        }
        if(abs(ap-bp)==1){
            break;
        }
        tot++;
    }
    }
    else{
        while(true){
            if(tot%2==0){
                ap--;
            }
            else{
                bp++;
            }
            if(abs(ap-bp)==1){
                break;
            }
            tot++;
        }
    }

    if(tot%2){
        cout<<"NO"<<endl;
    }
    else{
        cout<<"YES"<<endl;
    }
}

int main(){
    cin>>n;
    while(n--){
        sol();
    }
}

对于B题

这个题是让你去做区间修改,当时数据结构刚学完,于是就开始看到区间修改就开始去写线段树,由于他是值修改首尾的区间,所以就是说只要维护原数组的差分数组是不是就是可以了,但是似乎最后却发现这个没有那么好用。所以说最后在比赛场上做了半天也没有做出来,最后只好放弃了。后来与室友讨论了一下之后发现只要去注意判断就可以看了。首先,由于合成一种材料需要其他所有的材料,所以说,在这里,只有缺少一件材料才可以保证可以合成,如果说有两件材料的缺失,若是满足了其中一件,那么另一件的缺口会更大,所以说只能是一件缺失,在检验完这个之后,就可以去检验每一种材料是否有冗余,就可以了。

下面是AC 的代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;

int N;
int a[maxn],b[maxn];
void sol(){
    cin>>N;
    for(int i=1;i<=N;i++){
        cin>>a[i];
    }
    int tot=0;
    for(int i=1;i<=N;i++){
        cin>>b[i];
        if(b[i]>a[i]){
            tot++;
        }
    }
    if(tot>1){
        cout<<"NO"<<endl;
        return;
    }
    int margin=1e9;
    int need=0;
    for(int i=1;i<=N;i++){
        if(a[i]<b[i]){
            need=b[i]-a[i];
        }
        else{
            margin=min(margin,a[i]-b[i]);
        }
    }
    if (need>margin){
        cout<<"NO"<<endl;
    }
    else{
        cout<<"YES"<<endl;
    }
}

int T;
int main(){
    cin>>T;
    while(T--){
        sol();
    }
}

对于C题

下面这一个体也不算是一个有难度的题。但是确实是需要想一下的。

首先就是在这里对于一个矩阵。他会存在一条路径,想要让所有的行和列全部都和为一个固定的数,在这里一开始我看这里的限制条件这么多,那么肯定是一个搜索,但是在这里如果仔细观察一下就会发现,其实没有必要这么复杂,假设行数尾m,列数为n,那么在这里,由于每一行每一列的和是固定的,那么假设为x,在这之后,我们可以知道就是要去使用式子满足mx=nx,在这里,满足这一个式子的情况只有两个条件,第一个就是m=n,第二个就是x=0,于是,在这里,其实题目也说了会有多种答案,指的就是m=n的时候,但是,为了方便AC,就直接假设x=0就可以了,在这里面,对于每一个横着的行,要做的就是去将列给求和,对于每一个列,则是将横着的求和,这样子就可以过了。下面是AC的代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=2007;
ll grids[maxn][maxn];
inline void sol(){
    ll n,m;
    scanf("%lld %lld",&n,&m);
    string s;
    cin>>s;
    
    memset(grids,0,n*m*(sizeof(ll)));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%lld",&grids[i][j]);
        }
    }

    ll pos_x=1,pos_y=1;
    for(int p=0;p<n+m-2;p++){
        if(s[p]=='D'){
            ll num=0;
            for(int j=1;j<=m;j++){
                num+=grids[pos_y][j];
            }
            grids[pos_y][pos_x]=-num;
            pos_y++;
        }
        else if(s[p]=='R'){
            ll num=0;
            for(int i=1;i<=n;i++){
                num+=grids[i][pos_x];
            }
            grids[pos_y][pos_x]=-num;
           
            pos_x++;
        }
    }
    int num2=0;
    for(int i=1;i<=m;i++){
        num2+=grids[n][i];
    }
    grids[n][m]=-num2;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<grids[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main(){
    ll T;scanf("%lld",&T);
    while(T--){
        sol();
    }
}

D题

这个题目我觉得是一个比较有难度的题目,所以说就会讲的多一点,这个题是我看完题目之后完全没有思路的那一类题。我觉得他这个有一点像动态规划,实际上他和动态规划完全没有关系,我很惊讶他是一个贪心类似的题目。

对于这个题目,1.首先就是对于稻草人,他们之间的位置可以自由移动以确保乌鸦可以实现多次移动,但是对于每一个稻草人,他们之间的相对位置不可以改变。2.然后就是对于每一个稻草人,若是当前的稻草人离乌鸦所在的位置0有距离,那么这一次移动的时间是无法避免的,而且也没有办法拖延,第一个时间移动的必须是这个稻草人,毕竟乌鸦是只会检查其当前位置以及左手边是否存在稻草人。3.对于这个当前位置的稻草人,如果说稻草人在p位置,那么乌鸦就会存在于p+k的位置,在这里我们可以是为稻草人拥有乌鸦,然后在这里我去移动稻草人,乌鸦会持续不断的移动。然后我们假设乌鸦瞬移的距离是d,那么在这里,如果要最小化移动的时间,那么就要去最大化乌鸦的移动距离d,那么怎么做呢

在第二个样例里面,我们假设bi为第一个接受到乌鸦的地方,在这里
我们可以知道(b1,b2,b3)这里面的值为(0,2.5,4.5)。在这里,我们可以知道d=sum(min(k,bi+1 -bi ))并且额外定义bn+1=l,那么在这里可以知道a1+l-d=2+5-4.5=2.5。

接下来,对于怎么去选择bi,就会去需要讨论他们的最优的选择了。在时间T的时候,对于稻草人i,他会位于[ai-T,min(ai+T,l)]的区间中,然后接下来就可以知道这三种情况。

首先就是 bi-1+k(乌鸦被稻草人i-1持有的位置)<=ai-T(稻草人i的位置),在这里这一情况下。由于稻草人i要与乌鸦会合,所以说在这里,此时会和的位置是ai-T 和 bi-1+k的中点。所以可以知道这个时候bi=(ai-T+bi-1+k)/2

接着就是情况2,此时乌鸦位于 ai-T<=bi+k<=ai+T的位置,那么在这里,由于要最大化移动,所以说最好是能够让乌鸦作为接力棒可以马上刚好的到达当前的位置,那么接下来就是bi=bi-1+k。这时,乌鸦移动的空间是最大的。

对于情况3,若是ai+T<=bi-1+k,那么由于此时乌鸦已经超越了稻草人,那么此时此刻,就可以知道为bi=ai+T。
所以说在最后,这里bi=min(l,ai+T,max(bi-1+k,(ai-T+bi-1+k)/2))

这边就是bi的对待规律,下面是AC的代码。

#include<bits/stdc++.h>
using namespace std;

const int maxn=2e5+7;
int a[maxn];
inline void sol(){
    int n,k,l;
    scanf("%d %d %d",&n,&k,&l);
    double K=k;
    double L=l;
    memset(a,0,sizeof(a));
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    double T=a[0];
    double last_pt=0;
    double S=0;

    for(int i=1;i<n;i++){
        double this_pt=min(L,min(a[i]+T,
                            max(last_pt+K,
                                (a[i]-T+last_pt+K)/2.0)));
        T+=max(0.0,this_pt-last_pt-K);
        S+=min(K,this_pt-last_pt);
        last_pt=this_pt;
    }

    S+=min(K,L-last_pt);
    cout<<(int)round(2*(L-S+a[0]))<<endl;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        sol();
    }
    return 0;
}

就这四道题,后面的有时间在去补吧。先到这里了。

本文作者:芙芙芙啊

本文链接:https://www.cnblogs.com/fufufuf/p/18679088

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @ 2025-01-19 00:48  fufufuf  阅读(5)  评论(0编辑  收藏  举报