牛客网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\n",num[1]);
    }
    return 0;
}

 

 



posted @ 2018-11-04 19:33  安月冷  阅读(860)  评论(0编辑  收藏  举报