题解:CF1826E Walk the Runway

· · 题解

传送门

很容易想到 O(n^2m) 的 dp 做法。

转移方程为:$dp_i=dp_j+p_i$(如果可以转移)。 code: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=5005; int p[N],r[N][N]; bool can[N][N]; int dp[N]; int cnt[N];//储存映射关系 int n,m; bool cmp(int x,int y){ return r[1][x]<r[1][y]; } signed main(){ cin >> m >> n; for(int i=1;i<=n;i++)cin >> p[i]; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ cin >> r[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j)continue; can[i][j]=true; for(int k=1;k<=m;k++){ if(r[k][i]<=r[k][j]){ can[i][j]=false; break; } } } } for(int i=1;i<=n;i++){ cnt[i]=i; dp[i]=p[i];//自己 } sort(cnt+1,cnt+1+n,cmp);//将一维单调 可以证明 i 只能从 1~i-1转移 for(int i=1;i<=n;i++){ for(int j=1;j<i;j++){ if(can[cnt[i]][cnt[j]]){//如果可以转移 dp[cnt[i]]=max(dp[cnt[i]],dp[cnt[j]]+p[cnt[i]]); } } } int ans=0; for(int i=1;i<=n;i++){ ans=max(ans,dp[i]); } cout << ans << "\n"; return 0; } ``` ![](https://s21.ax1x.com/2024/12/07/pA78qhR.png) 但是很明显过不了。 考虑 bitset 优化,开 $n$ 个长度为 $n$ 的 bitset 数组 $b$。 $b_{i,j}=1$ 时表示可以从 $j$ 转移到 $i$。 然后,考虑每一维的预处理将逐位枚举变成 $\&$ 操作,此时时间复杂度从 $O(m)$ 降为 $O(\frac{m}{w})$(此时 $w=32$)。 这时,我们就可以用 $O(\frac{n^2m}{w})$(此时 $w=32$)的时间复杂度预处理出 $b$。 然后通过 dp 以 $O(nm\log_n)$ 的时间复杂度求出答案。 总时间复杂度: $$O(\frac{n^2m}{w}+nm\log_2n)$$ AC code: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=5005; int n,m; int p[N]; int a[N][N]; int cnt[N]; int nid; bool cmp(int x,int y){ return a[nid][x]<a[nid][y]; } bitset<5005>b[N],now; int dp[N]; signed main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin >> m >> n; for(int i=1;i<=n;i++){ cin >> p[i]; cnt[i]=i; b[i].set();//初始为全1 } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ cin >> a[i][j]; } } for(int k=1;k<=m;k++){ nid=k; now.reset(); sort(cnt+1,cnt+1+n,cmp);//对第k维排序 for(int i=1,j;i<=n;i++){ j=i; while(j<n&&a[k][cnt[j]]==a[k][cnt[j+1]])j++;//特判相等的情况 for(int l=i;l<=j;l++){ b[cnt[l]]&=now; } for(int l=i;l<=j;l++){ now[cnt[l]]=1; } i=j; } } int ans=0; for(int i=1;i<=n;i++){ dp[cnt[i]]=p[cnt[i]]; ans=max(ans,dp[cnt[i]]); } for(int i=1;i<=n;i++){ for(int j=1;j<i;j++){ if(b[cnt[i]][cnt[j]]){ dp[cnt[i]]=max(dp[cnt[i]],dp[cnt[j]]+p[cnt[i]]); ans=max(ans,dp[cnt[i]]); } } } cout << ans << "\n"; return 0; } ```