Codeforces1539 E. Game with Cards(思维+dp,st表倍增+二分 预处理)

Posted live4m

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces1539 E. Game with Cards(思维+dp,st表倍增+二分 预处理)相关的知识,希望对你有一定的参考价值。

题意:

在这里插入图片描述

解法:

一次只能换一个人的卡片,假如当前数值是x和y,此时x和y需要满足当前第i个限制.
假如卡片给x,那么y下一轮不变,y还需要满足第i+1个限制.
从这里容易想到每张卡片的持续效果一定是一段区间.

预处理lx[i]表示第i轮卡片给x,能向后扩展的最大位置,ly同理。

然后设计状态为dp[i][0/1],
dp[i][0]表示当前卡片给0,1能扩展的最大位置.
由于知道此时卡片给0,所以0的扩展长度也能知道,即lx[i].
这样的状态直接就能够表示两个数的扩展位置了.

剩下的就是O(n)的dp了,转移比较简单.

未解决的问题为:如何预处理lx[]和ly[].
我的做法是st表预处理f[i][j]=从区间i开始,向后走2^j-1,能得到的区间并.
对于每个位置i,二分其向后扩展的长度,用st表check能否扩展到即可.

code:

#include<bits/stdc++.h>
#define PI pair<int,int>
using namespace std;
const int maxm=1e5+5;
const int maxd=20;
int la[maxm],ra[maxm];
int lb[maxm],rb[maxm];
PI f[maxm][25];
int pos[2][maxm];
int pre[maxm][2];
int d[maxm][2];
int val[maxm];
int lg2[maxm];
int n,m;
PI merged(PI a,PI b){
    if(a.first==-1)return b;
    if(b.first==-1)return a;
    if(a.first==-2)return {-2,-2};
    if(b.first==-2)return {-2,-2};
    PI ans={max(a.first,b.first),min(a.second,b.second)};
    if(ans.first>ans.second)ans={-2,-2};//无交集
    return ans;
}
void init(){
    lg2[1]=0;
    for(int i=2;i<maxm;i++){
        lg2[i]=lg2[i-1];
        if((i&(i-1))==0)lg2[i]++;
    }
}
PI ask(int l,int r){
    int k=lg2[r-l+1];
    return merged(f[l][k],f[r-(1<<k)+1][k]);
}
void build(int* l,int* r,int* pos){
    for(int i=0;i<maxm;i++){
        for(int j=0;j<25;j++){
            f[i][j]={-1,-1};
        }
    }
    for(int i=1;i<=n;i++){
        f[i][0]={l[i],r[i]};
    }
    for(int j=1;j<=maxd;j++){
        for(int j=1;j<=maxd;j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                f[i][j]=merged(f[i][j-1],f[i+(1<<(j-1))][j-1]);
            }
        }
    }
    for(int i=1;i<=n;i++){
        int ans=0;
        int l=1,r=n-i+1;
        while(l<=r){
            int mid=(l+r)/2;
            PI x=ask(i,i+mid-1);
            if(x.first<=val[i]&&x.second>=val[i]){
                ans=mid,l=mid+1;
            }else{
                r=mid-1;
            }
        }
        pos[i]=i+ans-1;
    }
}
void dfs(int i,int j){
    if(i!=1){
        dfs(i-1,pre[i][j]);
    }
    printf("%d ",j);
}
void solve(){
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d%d%d",&val[i],&la[i],&ra[i],&lb[i],&rb[i]);
    }
    build(la,ra,pos[0]);
    build(lb,rb,pos[1]);
    PI last={0,1e9};
    for(int i=1;i<=n;i++){
        last=merged(last,{la[i],ra[i]});
        if(last.first<=0&&last.second>=0){
            d[1][1]=i;
        }else break;
    }
    last={0,1e9};
    for(int i=1;i<=n;i++){
        last=merged(last,{lb[i],rb[i]});
        if(last.first<=0&&last.second>=0){
            d[1][0]=i;
        }else break;
    }
    for(int i=2;i<=n;i++){
        for(int j=0;j<2;j++){//枚举当前状态
            for(int last=0;last<2;last++){//枚举上一张卡片的位置
                int p1=pos[last][i-1];
                int p2=d[i-1][last];
                if(j==last){
                    if(p1<i-1)continue;
                    if(p2>=d[i][j]){
                        d[i][j]=p2;
                        pre[i][j]=last;
                    }
                }else{//j!=last
                    if(p2<i-1)continue;
                    if(p1>=d[i][j]){
                        d[i][j]=p1;
                        pre[i][j]=last;
                    }
                }
            }
        }
    }
    for(int j=0;j<2;j++){
        int p1=pos[j][n];
        int p2=d[n][j];
        if(p1>=n&&p2>=n){
            puts("YES");
            dfs(n,j);
            return ;
        }
    }
    puts("NO");
}
signed main(){
    solve();
    return 0;
}

以上是关于Codeforces1539 E. Game with Cards(思维+dp,st表倍增+二分 预处理)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 850C E. Arpa and a game with Mojtaba

Codeforces Round #376 (Div. 2) E. Funny Game

Codeforces Round #167 (Div. 1) E. Dima and Game

Codeforces Round #727 (Div. 2) E. Game with Cards(巧妙dp的优化)

Codeforces Round #727 (Div. 2) E. Game with Cards(dp优化,从n^2到nlog到n)

[CF1539E]Game with Cards