ARC182A Chmax Rush!
一个比较糖的做法。
考虑如果第 i i i 次操作选择向左进行操作,则对于 j < i j<i j<i 且 V j > V i V_j>V_i Vj>Vi 的操作 j j j,一定有 P j > P i P_j>P_i Pj>Pi(否则无论第 j j j 次操作向左还是向右第 i i i 次操作都无法向左走),且对于这些操作 j j j,我们要求他们必须向右进行操作。
于是有一个很糖的 DP,设 d p i , j , 0 / 1 dp_{i,j,0/1} dpi,j,0/1 表示考虑前 i i i 个操作,所有 V ≥ j V \ge j V≥j 的操作全部向左/全部向右的方案数。
时间复杂度 O ( N Q ) O(NQ) O(NQ)。
cpp
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,q,cnt=0;
struct js
{
int p,v,id,vv;
}a[5005];
bool cmp(js x,js y)
{
return x.vv<y.vv;
}
bool cmpp(js x,js y)
{
return x.id<y.id;
}
int dp[5005][5005][2],dpp[5005];
int tree[5005],tr[5005];
int lowbit(int x){return x&(-x);}
void update(int x,int y)
{
for(int i=x;i<=cnt;i+=lowbit(i)) tree[i]=max(tree[i],y),tr[i]=min(tr[i],y);
}
int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i)) res=max(res,tree[i]);
return res;
}
int qu(int x)
{
int res=1e9+5;
for(int i=x;i;i-=lowbit(i)) res=min(res,tr[i]);
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=q;i++)
{
cin>>a[i].p>>a[i].vv;
a[i].id=i;
}
sort(a+1,a+1+q,cmp);
for(int i=1;i<=q;i++)
if(i==1||a[i].vv!=a[i-1].vv) cnt++,a[i].v=cnt;
else a[i].v=cnt;
sort(a+1,a+1+q,cmpp);
memset(tr,127,sizeof(tr));
dpp[0]=1;
for(int i=0;i<=cnt;i++) dp[0][i][0]=dp[0][i][1]=1;
for(int i=1;i<=q;i++)
{
a[i].v=cnt-a[i].v+1;
if(query(a[i].v-1)<a[i].p) dpp[i]=(dpp[i]+dp[i-1][a[i].v-1][0])%mod;
if(qu(a[i].v-1)>a[i].p) dpp[i]=(dpp[i]+dp[i-1][a[i].v-1][1])%mod;
for(int j=0;j<=cnt;j++)
if(j<a[i].v)
{
if(query(a[i].v-1)==0||query(j)==0) dp[i][j][0]=dpp[i];
else if(query(a[i].v-1)<a[i].p) dp[i][j][0]=(dp[i][j][0]+dp[i-1][a[i].v-1][0])%mod;
if(query(a[i].v-1)==0||query(j)==0) dp[i][j][1]=dpp[i];
else if(qu(a[i].v-1)>a[i].p) dp[i][j][1]=(dp[i][j][1]+dp[i-1][a[i].v-1][1])%mod;
}
else
{
if(query(a[i].v-1)==0)
{
dp[i][j][0]=dp[i-1][j][0];
dp[i][j][1]=dp[i-1][j][1];
}
}
update(a[i].v,a[i].p);
}
cout<<dpp[q];
return 0;
}