题意:

有一堆卡片,卡片上有1-4其中一个数,数字决定向前走的步数,走到某处就获得该点对应的分数,如何调整使用卡片顺序使得到达终点 n 时的得分最大。

分析:

动态规划每一步促使结果最优解,很明显思路是 dp 或者记忆化搜索(感觉搜索比较好写)
dfs(int k,int a1,int a2,int a3,int a4)

k表示当前位置,a1表示数字1卡片使用次数,a2表示数字2卡片使用次数,a3表示数字3卡片使用次数,a4表示数字4卡片使用次数,

由此有四个搜索方向:(前提是有卡片剩余
使用1卡片:dfs(k+1,a1+1,a2,a3,a4)
使用2卡片:dfs(k+2,a1,a2+1,a3,a4)
使用3卡片:dfs(k+3,a1,a2,a3+1,a4)
使用4卡片:dfs(k+4,a1,a2,a3,a4+1)

最后 if(k == n) 统计答案就行了
然后很自然地 TLE 了,O(4^120)还是太大了,要记忆化处理一下。
用dp[a1][a2][a3][a4] 记录每次局部最优答案即可。

代码:

#include <bits/stdc++.h>
#define mem(a, x) memset(a, x, sizeof(a))
using namespace std;
typedef long long ll;
int mod=1e9+7;
int a[400],b[150],c[5],dp[120][120][120][120];
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
int n,m,i,j;
int dfs(int k,int a1,int a2,int a3,int a4){
    if(k == n) return a[k];
    if(dp[a1][a2][a3][a4]) return dp[a1][a2][a3][a4];
    int cnt = 0;
    if(a1 < c[1]){
        cnt = max(cnt,dfs(k+1,a1+1,a2,a3,a4));
    }
    if(a2 < c[2]){
        cnt = max(cnt,dfs(k+2,a1,a2+1,a3,a4));
    }
    if(a3 < c[3]){
        cnt = max(cnt,dfs(k+3,a1,a2,a3+1,a4));
    }
    if(a4 < c[4]){
        cnt = max(cnt,dfs(k+4,a1,a2,a3,a4+1));
    }
    return dp[a1][a2][a3][a4] = cnt + a[k];
}
int main()
{
    cin>>n>>m;
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    for(i=1;i<=m;i++){
        cin>>b[i];
        c[b[i]]++;
    }
    cout<<dfs(1,0,0,0,0)<<endl;
}