CF1539E Game with Cards 題解
阿新 • • 發佈:2021-07-12
P.S.
補 VP 題。
Description.
卡老師手上拿著兩份程式碼,都有一個分數值。
剛開始卡老師一分都不會,所以兩份程式碼的分數值都是 \(0\)。
每次老K會給卡老師一份程式碼,卡老師必須且只能把他的一份程式碼卡成老K給的。
不過每次卡老師為了不被發現,所以每卡完一次都必須保證第一份程式碼的分數在 \([L_{i,0},R_{i,0}]\) 之間,第二份在 \([L_{i,1},R_{i,1}]\) 之間。
問卡老師能不能卡到最後。
Solution.
首先,我們考慮把他當做一段 \(0,1\) 串。
然後,模擬一下,我們會發現。
a ? c1 a c1 1 c2 c2 c1 0 c3 c3 c1 0 ... ck ck c1 0
如果有一段極長 \(0\) 串是合法的,當且僅當如下兩個條件同時滿足。
\[\forall i\in[l,r],L_{i,0}\le c_i\le R_{i,0} \]\[\forall i\in[l,r],L_{i,1}\le c_{l-1}\le R_{i,1} \]極長 \(1\) 同理。
我們觀察式子發現,如果從前往後推,其中的 \(C_{l-1}\) 不同會導致不具有單調性。
但是從後往前推我們只需要記錄 \(\max\{L_{i-1,?}\}\) 和 \(\min\{R_{i-1,?}\}\) 然後就可以 \(O(1)\) 判斷當前是否可行(對於條件 2。
所以我們從後往前,這樣對於一個轉移點,必定是它後面的一段相鄰區間可以轉移到它。
這樣就具有單調性了,可以優化了。
我們維護 \(0\)
然後就可以直接 \(O(n)\) 掃一遍的複雜度內 AC 此題。
Coding.
點選檢視程式碼
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}/*}}}*/
const int N=100005;int n,m,l[N][2],r[N][2],c[N],nx[N][2];
int main()
{
//以下程式碼中,wh 表示最靠前的可行位置,nw 表示當前第一個條件能否滿足
//ck 表示當前能否滿足兩個條件,L,R 分別表示當前最大左界和最小右界
read(n),read(m);int wh[2]={n+1,n+1};for(int i=1;i<=n;i++)
read(c[i]),read(l[i][0]),read(r[i][0]),read(l[i][1]),read(r[i][1]);
int nw[2]={1,1},ck[2]={0,0},L[2]={0,0},R[2]={m,m};for(int i=n;i;i--)
{
nw[0]&=l[i][0]<=c[i]&&c[i]<=r[i][0],nw[1]&=l[i][1]<=c[i]&&c[i]<=r[i][1];
L[0]=max(L[0],l[i][1]),R[0]=min(R[0],r[i][1]),L[1]=max(L[1],l[i][0]),R[1]=min(R[1],r[i][0]);
ck[0]=nw[0]&&(L[0]<=c[i-1]&&c[i-1]<=R[0]),ck[1]=nw[1]&&(L[1]<=c[i-1]&&c[i-1]<=R[1]);
(ck[0]?nx[i][0]=wh[0]:0),(ck[1]?nx[i][1]=wh[1]:0);
if(ck[0]) nw[1]=1,wh[1]=i,L[1]=0,R[1]=m;
if(ck[1]) nw[0]=1,wh[0]=i,L[0]=0,R[0]=m;
}
if(wh[0]>1&&wh[1]>1) return puts("No"),0;else puts("Yes");
for(int i=1,p=wh[1]>1;i<=n;i=nx[i][p],p^=1) for(int j=i;j<nx[i][p];j++) printf("%c ",'0'|p);
return putchar('\n'),0;
}
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{ #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; }/*}}}*/ const int N=100005;int n,m,l[N][2],r[N][2],c[N],nx[N][2]; int main() { //以下程式碼中,wh 表示最靠前的可行位置,nw 表示當前第一個條件能否滿足 //ck 表示當前能否滿足兩個條件,L,R 分別表示當前最大左界和最小右界 read(n),read(m);int wh[2]={n+1,n+1};for(int i=1;i<=n;i++) read(c[i]),read(l[i][0]),read(r[i][0]),read(l[i][1]),read(r[i][1]); int nw[2]={1,1},ck[2]={0,0},L[2]={0,0},R[2]={m,m};for(int i=n;i;i--) { nw[0]&=l[i][0]<=c[i]&&c[i]<=r[i][0],nw[1]&=l[i][1]<=c[i]&&c[i]<=r[i][1]; L[0]=max(L[0],l[i][1]),R[0]=min(R[0],r[i][1]),L[1]=max(L[1],l[i][0]),R[1]=min(R[1],r[i][0]); ck[0]=nw[0]&&(L[0]<=c[i-1]&&c[i-1]<=R[0]),ck[1]=nw[1]&&(L[1]<=c[i-1]&&c[i-1]<=R[1]); (ck[0]?nx[i][0]=wh[0]:0),(ck[1]?nx[i][1]=wh[1]:0); if(ck[0]) nw[1]=1,wh[1]=i,L[1]=0,R[1]=m; if(ck[1]) nw[0]=1,wh[0]=i,L[0]=0,R[0]=m; } if(wh[0]>1&&wh[1]>1) return puts("No"),0;else puts("Yes"); for(int i=1,p=wh[1]>1;i<=n;i=nx[i][p],p^=1) for(int j=i;j<nx[i][p];j++) printf("%c ",'0'|p); return putchar('\n'),0; }