Codeforces Round #707(Div.2)(A~B)

……又是两题滚粗……orz(人生重来算了)(不过好像based on Moscow Open Olympiad in Informatics,所以变难了不少(挠头),所以肯定不是我的问题)

A.Alexey and Train

本题是一道模拟题。首先各车站之间所需要的时间是不变的,a[i]-b[i-1]。然后在加上tmi就是这一段的路程。

因此我们先计算好原本的时间即a[i]-b[i-1]。然后再通过修改b[]即离站时间即可。注意要保证至少需要停留的时间。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define MAXN 105
using namespace std; 
typedef pair<int,int> pii;
int t,n,tm[MAXN],ans;
struct sta{
    int a,b,lastt;
}s[MAXN];
int main(){ 
    scanf("%d",&t);
    s[0].b=0;
    while(t--){
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&s[i].a,&s[i].b);
            s[i].lastt=(s[i].b-s[i].a)/2 + ((s[i].b-s[i].a)%2);
            s[i].a-=s[i-1].b;
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&tm[i]);
        for(int i=1;i<=n;i++){
            ans=s[i].a+s[i-1].b+tm[i];//ans为到第i个站点的时间  
            if(ans+s[i].lastt>s[i].b)
                s[i].b=ans+s[i].lastt;//更新离开时间 
//            printf("经过%d站点,车到达时间为%d,离开时间为%d,持续时间为%d\n",i,s[i].a,s[i].b,s[i].lastt);
        }
        printf("%d\n",ans); 
    }
}

B.Napoleon Cake

这题我一开始直接暴力。从1~n遍历a数组然后对每个a数组至上向下涂色。(当然t了)

然后我们思考一下。这个过程重复的就是已经涂过色的部分还要再涂一遍。

这时候我想到了前几天刚学的KMP算法。(虽然好像做麻烦了qwq,看到大佬的题解好像可以直接用差分做)

建了一个next数组。在至上向下涂色的过程中,如果遇到已经涂色的块了,就next到他的下一个未涂色块中。如果a能支撑到那里的话就涂色

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define MAXN 200005
using namespace std; 
typedef pair<int,int> pii;
int t,n,a[MAXN],vis[MAXN],next1[MAXN];
int find_next(int x,int temppp=0){//temppp若无传参,则默认为0,不影响 
    if(x==0){
        for(int i=temppp;i>0;i--)
            next1[i]=0;
    }
    int temp=x;
    while(vis[temp])
        temp=next1[temp];
    next1[x]=temp;
    return temp;
}
int main(){ 
    scanf("%d",&t);
    next1[0]=0;
    while(t--){
        memset(vis,0,sizeof(vis));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            next1[i]=i-1;//初始化,下一个不是0的就是自己的下一块 
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            if(!a[i])
                continue;
            int temp=1;
            while(temp<=a[i]){
                if(vis[i-temp+1]){//如果这一块已经涂过了 
                    int nexttemp=find_next(i-temp+1);//找下一个没涂过的 
                    if(!nexttemp)//如果没了 
                        break;
                    else
                        temp+=(i-temp+1-nexttemp);//如果还有。这样不仅修改了下标,还修改了涂色次数。 
                }else{
                    vis[i-temp+1]=1;
                    if(i-temp==0){
                        find_next(0,i);//全部涂完。已有的块全部指向0,表示下面没有了。 
                        break;
                    }
                    if(temp==a[i]){
                        next1[i]=find_next(i);//记录最上面的一个已经涂色的。 
                    }
                    temp++;
                }
            }
        }
        for(int i=1;i<=n;i++)
            printf("%d ",vis[i]);
        printf("\n");
    } 
}

 

posted @ 2021-03-13 21:19  mikku  阅读(63)  评论(0)    收藏  举报