[CF1826E] Walk the Runway 题解

· · 题解

首先可以直接 dp,先按 r_{1,i} 排序,设 f_i 表示考虑到第 i 个人且选择第 i 个人的最大价值,则转移为 \displaystyle f_i=p_i+\max_{j<i,j\isin G_i}f_{j},其中 G_i 表示所有满足 \forall 1\le k\le m,r_{k,i}>r_{k,j}j 构成的集合。注意到整个 dp 是 \mathcal{O}(n^2) 的,于是只需要快速求出 G_i 即可。

若 $m=1$,则问题是简单的,维护一个集合 $S$,初始为空,按 $r_{1,i}$ 从小到大往 $S$ 中加入 $i$,则 $G_x$ 就可以视作加入 $x$ 之前的集合 $S$,不妨设此时的集合 $S$ 为 $T_{1,x}$。 接下来考虑 $m$ 更大时的做法,我们一样可以对每一行维护 $S$,然后求出所有的 $T_{i,j}$,则 $G_{x}=\bigcap_{i=1}^m T_{i,x}$。 直接将 $S,T_{i,j},G_i$ 视作 bitset 即可维护。具体实现时不需要存储 $T_{i,j}$,只需要对每一行动态维护 $S$ 并记录 $G_i$ 即可。还需要注意 $r$ 相等的情况。 时间复杂度 $\mathcal{O}(\frac{n^2m}{\omega})$,其中 $\omega=64$,CF 把时限卡这么满也是有点少见了。 ::::info[code] ```cpp #include<bits/stdc++.h> #define pb emplace_back #define pob pop_back #define mp make_pair using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; const ll maxn=5007; ll n,m,a[maxn],f[maxn],v[maxn],id[maxn],ans; bitset<maxn> stt,g[maxn]; int main(void){ //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); ios::sync_with_stdio(0); cin.tie(0); cin>>m>>n; for(ll i=1;i<=n;i++) cin>>a[i]; for(ll i=1;i<=n;i++)for(ll j=1;j<=n;j++) g[i][j]=1; for(ll i=1;i<=m;i++){ stt.reset(); for(ll j=1;j<=n;j++) cin>>v[j],id[j]=j; sort(id+1,id+1+n,[&](ll x,ll y){return v[x]<v[y];}); for(ll l=1,r;l<=n;l=r+1){ for(r=l;r<=n;r++){ g[id[r]]&=stt; if(r==n||v[id[r]]!=v[id[r+1]]) break; } for(ll j=l;j<=r;j++) stt[id[j]]=1; } } for(ll t=1,i,j;t<=n;t++){ i=id[t],f[i]=a[i]; for(ll x=1;x<t;x++){ j=id[x]; if(g[i][j]) f[i]=max(f[i],f[j]+a[i]); } ans=max(ans,f[i]); } cout<<ans<<"\n"; return 0; } ``` ::::