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)