CodeForces - 1453F(dp)

90nwyn

2020-12-05 12:40:27

Personal

[题目链接](https://vjudge.net/problem/CodeForces-1453F) ------------ 设$dp[i][j](i \leq j)$为存在某一点$k(k<i)$,有且仅有一条路径到达点$i$,同时该点能到达的最远的位置为$j$(即$k+a_{k}=j$)时的最优解 考虑如何状态转移 更新点$i$的状态时,从$i-1$枚举到$1$,假设当前枚举到点$j$且满足$j+a_j \geq i$,记$cnt$为点$j+1$到点$i-1$中,有多少点能直接一次到达点$i$,那么为了使得点$j$到点$i$的路径唯一,该$cnt$个点应当全部变为$0$,所以状态转移方程为: $dp[i][j+a_j]=min(dp[i][j+a_j], min(dp[j][j],dp[j][j+1],...dp[j][i-1]) +cnt)$ 每次更新完点$i$的状态后, 维护前缀最小值$suf[j][i-1]=min(dp[j][j],dp[j][j+1],...dp[j][i-1])$ 所以$dp[i][j+a_j]=min(dp[i][j+a_j], suf[j][i-1]+cnt),if$ $(j<i \leq j+a_j)$ ------------ ```cpp #include <bits/stdc++.h> using namespace std; const int M=3e3+10,inf=0x3f3f3f3f; int n,dp[M][M],a[M]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=2;i<=n;i++) { for(int j=i;j<=n;j++)dp[i][j]=inf; int c=0; for(int j=i-1;j>=1;j--) if(j+a[j]>=i) dp[i][j+a[j]]=min(dp[i][j+a[j]],dp[j][i-1]+c),c++; for(int j=i+1;j<=n;j++)dp[i][j]=min(dp[i][j],dp[i][j-1]); } printf("%d\n",dp[n][n]); } return 0; } /* 3 8 4 5 4 2 1 0 1 0 4 3 1 1 0 5 2 2 2 1 0 */ ```