zoukankan      html  css  js  c++  java
  • 牛客网NOIP赛前集训营-提高组(第八场)

    染色

    链接:https://ac.nowcoder.com/acm/contest/176/A
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 524288K,其他语言1048576K
    64bit IO Format: %lld

    题目描述

    fizzydavid和leo有n个方格排成一排,每个方格初始是白色。fizzydavid有红色染料,leo有蓝色染料。他们共进行了m次操作,在每次操作中,fizzydavid或者leo会选择若干个(可以是零个)连续相邻的方格并用自己的染料给这些格子染色。当一个格子被染成某个颜色时,这种染料会覆盖之前这个格子上的颜色。

    现在你并不知道他们每次操作选择了哪些格子,只知道每次操作是谁进行的,以及最终这n个方格的颜色。你需要判断是否存在某种选择格子的方式使得操作完之后n个方格的颜色与给定的相同。你还发现,n个格子最终都不是白色。

    输入描述:

    第一行包含一个整数T,表示本组数据共有T组测试点。

    对每组测试点的第一行是一个由R和B组成的字符串s表示最终格子的颜色。R表示红色,B表示蓝色,同时字符串的长度为n。

    第二行是一个由F和L组成的字符串t表示m次操作,F表示某次是fizzydavid操作,L表示是leo操作,同时字符串的长度为m。

    所有数据满足T<=20。

    50%的数据满足n,m<=15

    80%的数据满足n,m<=100

    100%的数据满足n,m<=100000

    输出描述:

    对每组测试点输出一行,如果满足条件输出Yes否则输出No。
    示例1

    输入

    复制
    3
    R
    FL
    RRRBR
    FFFF
    BRRBBRB
    LFL

    输出

    复制
    Yes
    No
    Yes

    说明

    对第一个测试点,第二次操作可以是空的。

    对第二个测试点,s中有B,但是t中没有L,因此不合法。

    对第三个测试点,BBBBBBB -> BRRRRRB -> BRRBBRB就是合法的。

    /*
    正序涂色比较难操作,因为一个格子可以被染很多次。可以考虑倒序涂色
    会发现每个格子最多会被染色一次。
    因为后面的染色会覆盖前面的染色。
    所以可以染完色后把格子删掉。然后合并删掉两边的同色格子。 
    考虑贪心
    1.一定会删除尽量多的连续格子 2.一定会优先删中间的格子(删两边没有合并)。
    
    具体实现不必直接操作。只需要统计每个连续的同色的区域个数然后每次做减法就好。 
    最优操作和不优的操作在这里不会体现出来,这样可以默认是最优操作。 
    */
    #include<bits/stdc++.h>
    
    #define N 100007
    
    using namespace std;
    int n,m,T;
    char a[N],opt[N];
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",a+1);scanf("%s",opt+1);
            n=strlen(a+1);m=strlen(opt+1);
            int r=0,b=0;
            for(int i=1; i<=n; i++)
            {
                if(a[i]!=a[i-1])
                {
                    if(a[i]=='R') r++;
                    else b++;
                }
            }
            for(int i=m; i>=1; i--)
            {
                if(opt[i]=='F')
                {
                    r--;if(b>=2) b--;
                }
                else
                {
                    b--;
                    if(r>=2) r--;
                }
            }
            if(r<=0&&b<=0) puts("Yes");
            else puts("No");
        }
        return 0;
    }

     

    链接:https://ac.nowcoder.com/acm/contest/176/B
    来源:牛客网

    推箱子
    时间限制:C/C++ 2秒,其他语言4秒
    空间限制:C/C++ 524288K,其他语言1048576K
    64bit IO Format: %lld

    题目描述

    在平面上有n个箱子,每个箱子都可以看成一个矩形,两条边都和坐标轴平行。任何两个矩形都不相交,但可能有某个点或某条边重合。约定x轴正方向为右,y轴正方向为上。

    现在Fizzydavid要推这些箱子。他会选择某个箱子开始,并以每秒1个单位的速度使这个箱子向右移动。如果路上正面碰上某个箱子,被碰上的箱子会在碰到的那个瞬间开始进入运动状态,以1个单位的速度向右移动,不会转动或改变运动方向。

    准确地说,在某个时刻一个箱子i处于移动状态当且仅当:i是选择的箱子;或者存在一个处于移动状态的箱子j,它的右边界等于箱子i的左边界,且它们在y轴上的投影的公共长度>0。你可以发现在这种情况下,任意时刻每个矩形仍然不相交。

    Fizzydavid告诉了你所有的信息,需要你求出k秒后每个矩形的位置。

    输入描述:

    第一行两个整数n,t和k。Fizzydavid开始选择的是输入的第t个矩形。

    接下来n行每行四个整数x1,i,y1,i,x2,i,y2,i,表示矩形的左下角坐标是(x1,i,y1,i),右上角坐标是(x2,i,y2,i)。

    对于30%的数据,k<=100。

    对于另外40%的数据,n<=1000。

    对于所有的数据,n<=105,1<=t<=n,1<=k<=109,所有坐标都在-109和109之间。保证任意两个矩形不相交。

    输出描述:

    输出一行n个整数,第i个整数表示k秒后第i个矩形的左下角的x坐标。你可以发现只要知道这个值就能唯一确定矩形的位置。
    示例1

    输入

    复制
    3 1 5
    0 0 1 1
    1 0 2 1
    4 0 5 1

    输出

    复制
    5 6 7

    说明

    在刚开始时,前两个矩形就处于移动状态。在第二秒开始时,第三个矩形进入移动状态。
    /*
    copy
    发现矩形之间可以连边
    可以转化为类似最短路的问题。
    但只能过40
    发现有序处理矩形是不严格n^2的,竟然跑过70...     
    */
    #include<bits/stdc++.h> 
    #define int long long
    #define inf 66666666666ll
    #define max(a,b) (a>b?a:b)
    using namespace std;
    int n,t,k;
    struct node
    {
        long long x1,y1,x2,y2;
        int pos;
        bool operator <(const node a)const
        {
            if(x1!=a.x1) return x1<a.x1;
            return y1<a.y1;
        }
    } num[100010];
    int tim[100010];
    long long answer[100010];
    inline long long min(long long a,long long b)
    {
        return a<b?a:b;
    }
    signed main()
    {
        scanf("%lld%lld%lld",&n,&t,&k);
        for(int i=1; i<=n; i++) scanf("%lld%lld%lld%lld",&num[i].x1,&num[i].y1,&num[i].x2,&num[i].y2),num[i].pos=i;
        sort(num+1,num+n+1);
        for(int i=1; i<=n; i++) tim[i]=inf;
        int start=1;
        while(num[start].pos!=t && start<=n) start++;
        tim[start]=0;
        for(int i=start+1; i<=n; i++)
        {
            int ans=inf;
            for(int j=start; j<i; j++)
            {
                if((num[j].y1>=num[i].y1 && num[j].y1<num[i].y2) || (num[j].y1<=num[i].y1 && num[j].y2>num[i].y1))
                    ans=min(ans,tim[j]+num[i].x1-num[j].x2);
            }
            tim[i]=ans;
            if(ans<inf && ans>k) break;
        }
        for(int i=1; i<=n; i++) answer[num[i].pos]=num[i].x1+max(k-tim[i],0);
        for(int i=1; i<=n; i++)
            printf("%lld ",answer[i]);
    }
    70暴力
    /*
    正解有地方不太懂
    时间比较紧了就这样吧... 
    */
    #include<bits/stdc++.h>
    
    #define N 100007
    
    #define ls cur<<1
    #define rs cur<<1|1
    
    using namespace std;
    int n,t,k,a[N],num,pre[N],ans[N];
    struct qwq{
        int x1,y1,x2,y2,id;
        bool operator <(const qwq &x) const{
            return x1<x.x1||(x1==x.x1&&y1<x.y1);
        }
    } m[N];
    struct Node{
        int mx,lazy;
    } tr[N<<2];
    
    inline void pushup(int cur)
    {
        tr[cur].mx=max(tr[ls].mx,tr[rs].mx);
    }
    
    inline void pushdown(int cur)
    {
        if(tr[cur].lazy!=-1)
        {
            tr[ls].mx=tr[cur].lazy,tr[rs].mx=tr[cur].lazy;
            tr[ls].lazy=tr[rs].lazy=tr[cur].lazy;
            tr[cur].lazy=-1;
        }
    }
    
    inline void update(int cur,int l,int r,int L,int R,int c)
    {
        if(L<=l && r<=R)
        {
            tr[cur].lazy=tr[cur].mx=c;
            return;
        }
        pushdown(cur);
        int mid=(l+r)>>1;
        if(L<=mid) update(ls,l,mid,L,R,c);
        if(mid<R) update(rs,mid+1,r,L,R,c);
        pushup(cur);
    }
    
    inline int query(int cur,int l,int r,int L,int R)
    {
        if(L<=l && r<=R) return tr[cur].mx;
        pushdown(cur);
        int mid=(l+r)>>1,res=0;
        if(L<=mid) res=max(res,query(ls,l,mid,L,R));
        if(mid<R) res=max(res,query(rs,mid+1,r,L,R));
        return res;
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&t,&k);
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d%d",&m[i].x1,&m[i].y1,&m[i].x2,&m[i].y2);
            m[i].id=i;
            a[++num]=m[i].y1; a[++num]=m[i].y2;
        }
        sort(a+1,a+num+1);
        num=unique(a+1,a+num+1)-a-1;
        sort(m+1,m+n+1);
        for(int i=1; i<=n; i++)
        { 
            ans[m[i].id]=m[i].x1;
            if(m[i].id==t)
            {
                int x=lower_bound(a+1,a+num+1,m[i].y1)-a;
                int y=lower_bound(a+1,a+num+1,m[i].y2)-a;
                update(1,1,num,x,y,m[i].x2-m[i].x1);
                t=i;
                break;
            }
        }
        k+=m[t].x1;
        ans[m[t].id]=k;
        for(int i=t+1; i<=n; i++)
        {
            int x=lower_bound(a+1,a+num+1,m[i].y1)-a;
            int y=lower_bound(a+1,a+num+1,m[i].y2)-a;
            int pre=query(1,1,num,x,y);
            if(!pre || pre+k<=m[i].x1) ans[m[i].id]=m[i].x1;
            else
            {
                ans[m[i].id]=k+pre;
                update(1,1,num,x,y,m[i].x2-m[i].x1+pre);
            }
        }
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        return 0;
    }

     

    链接:https://ac.nowcoder.com/acm/contest/176/C
    来源:牛客网

    Revue
    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 524288K,其他语言1048576K
    64bit IO Format: %lld

    题目描述

    梦想的revue拉开帷幕,你需要和你的对手争夺position zero。revue的形式是一个游戏,游戏中有一排共n个位置可以争夺,每个位置有一个权值,第i个位置的权值为ai。游戏是回合制的,你和你的对手轮流进行操作,你是先手。每一回合,进行操作的玩家需要在这一排位置的两端一共标记K个位置,一个位置最多只能被标记一次,操作必须保证每时每刻未被标记的位置是连续的。最终剩下的一个未标记的位置的权值就是游戏的得分,你需要使这个得分最大,你的对手需要使这个得分最少。保证最后只剩下一个位置未被标记,即n-1是K的倍数。若你和你的对手都使用最优策略进行操作,请问这个游戏的最终得分是多少。

    输入描述:

    本题有多组测试数据。第一行一个整数T表示测试数据组数。接下来分别是T组数据。每组数据内:
    为了避免输入过慢,输入数据分为两种。若第一行为raw,则表示这组数据是输入给定的。第二行会有两个整数n和K。第三行有n个整数,第i个数表示ai。若第一行为random,则表示这组数据是随机生成的。第二行会有4个整数n,K,S,P。表示a1=S, ai= (2333ai-1+6666) mod P。(mod表示取模操作)
    20%的数据 1 ≤ n,K ≤ 10
    40%的数据保证 1 ≤ n,K ≤ 1000
    另外20%的数据保证 1 ≤ n ≤ 10000, K ≥ 100
    80%的数据保证 1 ≤ n,K ≤ 10000
    100%的数据保证n-1是K的倍数,0 ≤ T ≤ 100,1 ≤ K < n ≤ 100000,0 ≤ S, P, ai ≤ 109,类型为raw的数据的n的和不超过500000。

    输出描述:

    每组数据输出一行表示答案,一共输出T行。
    示例1

    输入

    复制
    3
    raw
    5 2
    5 3 4 2 1
    raw
    7 2
    5 3 4 2 1 6 7
    random
    13 3 2 20

    输出

    复制
    3
    4
    2

    说明

    对于样例中第一个测试数据,初始有5个位置未标记,他们的权值是:

    5 3 4 2 1

    第一回合,最优策略下你选择标记右端的两个位置(即第4个位置和第5个位置),剩下来未被标记的位置的权值为:

    5 3 4

    第二回合,最优策略下你的对手选择标记左端的一个位置和右端的一个位置(即第1个位置和第3个位置),剩下来未被标记的位置的权值为:

    3

    这个游戏的最终得分为3。注意当你和你的对手都是用最优策略进行操作时,游戏最终的得分是唯一的。

    #include<bits/stdc++.h>
    
    #define N 5001
    #define M 100007
    #define ll long long
    #define inf 0x3f3f3f3f
    
    using namespace std;
    ll n,m,k,s,p,ans,cnt,T;
    ll f[N][N],a[M],sum[M];
    bool opt;
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    ll min(ll a,ll b){return a<b?a:b;}
    
    void solve1()
    {
            for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1;
            for(int i=1;i<=n;i++) f[i][i]=a[i];
            if(((n-1)/k)%2==0) opt=0;
            else opt=1;
            
            for(int L=k;L<n;L+=k) 
            {
                if(L%k!=0) continue;
                opt^=1;
                for(int i=1;i+L<=n;i++)
                {
                    int j=i+L;ll res1=inf,res2=0;
                    res1=min(res1,f[i+k][j]); res2=max(res2,f[i+k][j]);
                    res1=min(res1,f[i][j-k]); res2=max(res2,f[i][j-k]);
                    for(int x=1;x<k;x++)
                    {
                        if(i+x>j-k+x) break;
                        if(i+x>n || j-k+x<0) continue;
                        if(f[i+x][j-k+x]==-1) continue;
                        res1=min(res1,f[i+x][j-k+x]); res2=max(res2,f[i+x][j-k+x]);        
                    }
                    if(opt) f[i][j]=res1;
                    else f[i][j]=res2;
                }
            }
            ans=max(ans,f[1][n]);
    }
    
    int main()
    {
        freopen("data.txt","r",stdin);
        freopen("2.out","w",stdout);
        cin>>T;
        while(T--)
        {
            ans=0;
            char ch[5];scanf("%s",ch);
            if(ch[2]=='w')
            {
                n=read();k=read();
                for(int i=1;i<=n;i++) a[i]=read();
            }
            else
            {
                n=read();k=read();a[1]=s=read();p=read();
                for(int i=2;i<=n;i++) a[i]=((2333*a[i-1])%p+6666)%p;
            }
            if(n<=5000 && k<=5000) 
            {
                solve1();//solve2();
            }
            //else solve2();
            cout<<ans<<endl;
        }
        return 0;
    }
    /*
    1
    raw
    7 2
    1 1 9 2 2 2 2
    
    ans=9
    */
    40暴力
    /*
    60暴力 
    改变一下40暴力dp状态,定义f[i]为以i开头的长度为x*k+1的dp值
    这样f[i]就可以对每次操作用单调队列维护答案了。 
    */
    #include<bits/stdc++.h> 
    
    #define N 100007
    #define ll long long
    
    char ch[111];
    int T,n,k,Tim,head,tail,S,P;
    ll num[N],Q[N];;
    
    ll Nxt(ll v){return (2333LL*v+6666LL)%P;}
    
    bool cmp(ll a, ll b, int d)
    {
        if(d) return a<=b;
        return a>=b;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",ch);
            if(ch[2]=='w')
            {
                scanf("%d%d",&n,&k);
                for(int i=1;i<=n;++i) scanf("%lld", &num[i]);
            }
            else
            {
                scanf("%d%d%lld%lld",&n,&k,&S,&P);
                num[1]=S;
                for(int i=2;i<=n;++i)   num[i]=Nxt(num[i-1]);
            }
            Tim=(n-1)/k;
            for(int t=1,d=Tim&1;t<=Tim;++t,d=!d)
            {
                head=tail=0;
                memset(Q,0,sizeof Q);
                for(int i=1,q=1-k;i<=n;++i,++q)
                {
                    while(head<tail && Q[head]<q) ++head;
                    while(head<tail && cmp(num[Q[tail-1]], num[i], d))   --tail;
                    Q[tail++]=i;
                    if(q>0)  num[q]=num[Q[head]];
                }
                n-=k;
            }
            printf("%lld
    ",num[1]);
        }
        return 0;
    }

     

     



  • 相关阅读:
    sql server:Monty Hall problem (蒙提霍尔问题)
    sql server: Graphs, Trees, Hierarchies and Recursive Queries
    csharp:SMO run sql script
    csharp: sum columns or rows in a dataTable
    sql server: quering roles, schemas, users,logins
    sql: Query to Display Foreign Key Relationships and Name of the Constraint for Each Table in Database
    Hadoop基本概念
    OVS架构解析
    Linux下实现修改IP选项字段
    linux下实现UDP通信
  • 原文地址:https://www.cnblogs.com/L-Memory/p/9905358.html
Copyright © 2011-2022 走看看