首页 > 试题广场 >

小美和大富翁

[编程题]小美和大富翁
  • 热度指数:907 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\,\,\,\,\,\,\,\,\,\,小美在玩《大富翁》游戏,游戏中有 n+1 个城市排成一排,编号从 0n ,第 i 个城市上有一个数字 a_i ,表示到达第 i 个城市可以获得 a_i 枚金币。
\,\,\,\,\,\,\,\,\,\,每一轮开始时小美会获得四张卡牌,分别可以跳跃 1、2、3、4 个城市,例如小美可以从城市1跳跃 3 个城市到达城市4。当小美使用完这 4 张卡牌后,会开启新的一轮。
\,\,\,\,\,\,\,\,\,\,初始时,小美拥有 0 枚金币,在任意时刻,小美的金币数量都必须大于等于 0 ,小美想知道她从第 0 个城市出发,到达第 n 个城市最多可以获得多少枚金币。

输入描述:
\,\,\,\,\,\,\,\,\,\,第一行输入一个整数 n\ (1 \leq n \leq 10^5) 表示城市个数。
\,\,\,\,\,\,\,\,\,\,第二行输入 n 个整数 a_1,a_2,\dots,a_n\ (-10^9 \leq a_i \leq 10^9) 表示到达城市1到n可以获得的金币数量(第0个城市无法获得金币)。


输出描述:
\,\,\,\,\,\,\,\,\,\,在一行上输出一个整数表示答案;如果无法到达第 n 个城市,则输出 -1
示例1

输入

10
-1 2 3 4 -9 -9 -1 3 -1 -1

输出

9

说明

最优的方法是:
第 1 步:使用跳跃 3 的卡牌,从 0 跳到 3 ,获得 3 枚金币;
第 2 步:使用跳跃 1 的卡牌,从 3 跳到 4 ,获得 4 枚金币,共有 7 枚金币;
第 3 步:使用跳跃 4 的卡牌,从 4 跳到 8 ,获得 3 枚金币,共有 10 枚金币;
第 4 步:使用跳跃 2 的卡牌,从 8 跳到 10 ,获得 -1 枚金币,共有 9 枚金币。
我们将从0~n按每十步分为若干段。可以发现,由于每次使用完 1 2 3 4 后会重置,于是必定在每次重置之前,都只能跳跃10步。我们找到每次轮回中,如何排列 1 2 3 4 ,使得这一次跳跃10步,能得到最大金币总数,然后将每十步的最大金币加起来即可。不过,这只是找到了 n / 10 次 十步 的最大金币总和,而 n % 10 要另外枚举。
我们首先得到 1 2 3 4 的全排列,共24种,每次跳跃10步,就枚举24种可能取最大值,n / 10 次十步跳跃加起来即可。当计算 n % 10 时,只需枚举这24种可能,取每种可能的前序,如果能跳跃到 n 则统计一次答案。
注意,每次跳跃都要保证总金币为 0 。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main {

    static List<List<Integer>> list = new ArrayList<>();
    static boolean[] vis = new boolean[5];
    static int[] b = new int[4];

    private static void fun(int cnt) {
        if (cnt == 4) {
            list.add(Arrays.asList(b[0], b[1], b[2], b[3]));
            return;
        }
        for (int i = 1; i <= 4; i++) {
            if (!vis[i]) {
                vis[i] = true;
                b[cnt++] = i;
                fun(cnt);
                vis[i] = false;
                cnt --;
            }
        }
        return;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        Arrays.fill(vis, false);
        int n = in.nextInt();
        int[] a = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            a[i] = in.nextInt();
        }
        fun(0);
        int x = n / 10;
        int y = n % 10;
        int now = 0;
        long ans = 0;
        for (int i = 0; i < x; i++) {
            long res = (long)-1e18;
            boolean q = false;
            for (List<Integer> lst : list) {
                int u = now;
                long temp = 0;
                int j = 0;
                for (j = 0; j < 4; j++) {
                    u += lst.get(j);
                    temp += 1l * a[u];
                    if (ans + temp < 0) break;
                }
                if (j == 4) q = true;
                res = Math.max(res, temp);
            }
            if (!q) {
                System.out.println(-1);
                return;
            }
            now += 10;
            ans += res;
        }
        long res = ans;
        boolean q = (now == n);
        for (List<Integer> lst : list) {
            int u = now;
            long temp = 0;
            for (int i = 0; i < 4; i++) {
                u += lst.get(i);
                if (u > n) break;
                temp += 1l * a[u];
                if (res + temp < 0) break;
                if (u == n) {
                    q = true;
                    ans = Math.max(ans, res + temp);
                    break;
                }
            }
        }
        System.out.println(q ? ans : -1);
    }
}


发表于 2024-09-03 15:53:00 回复(0)
给一个让你眼前一亮的,直接把24种可能全部列出来。

#include <iostream>
#include <vector>
using namespace std;

vector<vector<int>> mode({{1, 2, 3, 4}, {1, 2, 4, 3}, {1, 3, 2, 4}, {1, 3, 4, 2}, {1, 4, 2, 3}, {1, 4, 3, 2},
    {2, 1, 3, 4}, {2, 1, 4, 3}, {2, 3, 1, 4}, {2, 3, 4, 1}, {2, 4, 1, 3}, {2, 4, 3, 1},
    {3, 1, 2, 4}, {3, 1, 4, 2}, {3, 2, 1, 4}, {3, 2, 4, 1}, {3, 4, 1, 2}, {3, 4, 2, 1},
    {4, 1, 2, 3}, {4, 1, 3, 2}, {4, 2, 1, 3}, {4, 2, 3, 1}, {4, 3, 1, 2}, {4, 3, 2, 1}});

long long getAns(vector<int>& a, long long x, int step) {
    if (x < 0) return -1;
    if (step >= a.size() - 1) return x;
    long long ans = -1;
    for (auto& v : mode) {
        long long sum = x;
        int k = step;
        for (int& i : v) {
            k += i;
            if (k >= a.size()) break;
            sum += a[k];
            if (sum < 0 || k == a.size() - 1) break;
        }
        if (sum > ans && k < a.size()) ans = sum;
    }
    return getAns(a, ans, step + 10);
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    cout << getAns(a, 0, 0);
}

发表于 2024-12-25 14:49:02 回复(0)
回溯
n = int(input())
arr = list(map(int, input().split()))


def step(start, gold):
    if len(stack) == 4 or start == n-1:
        earn.append(gold)
    for i in card:
        idx = start + i
        if i not in stack and idx < n:
            gold_idx = gold + arr[idx]
            if gold_idx >= 0:
                stack.add(i)
                step(idx, gold_idx)
                stack.remove(i)


card = [1, 2, 3, 4]
stack = set()
money = 0
flag = True
cur_start = -1
while cur_start + 1 < n:
    earn = []
    step(cur_start, money)
    if earn:
        money = max(earn)
    else:
        flag = False
        break
    cur_start += 10
print(money if flag else -1)


编辑于 2024-09-21 18:54:25 回复(0)
只有四个卡牌,全排列24种情况,直接打表比回溯递归应该是简单很多的
发表于 2025-05-19 14:45:53 回复(0)
有坑记录一下,每10步为一轮,每轮的金钱要继承,我之前清零,再累加每轮,因为每步的金钱>=0,这样做会有保守的解。
#include <iostream>
#include<vector>
using namespace std;

long long res = INT32_MIN;
void backtracking(const vector<long long>& city, long long pos, long long money, vector<bool>& used, int step)
{
    if(money < 0)
        return ;
    if(pos > city.size()-1)
        return ;
    if(step == 4 || pos == city.size()-1)
    {
        res = max(res, money);
        return ;
    }

    for(int i=1; i<=4; i++)
    {
        if(used[i]==false && money+city[pos+i]>=0 && pos+i<=city.size()-1)
        {
            used[i]=true;
            backtracking(city, pos+i, money+city[pos+i], used, step+1);
            used[i]=false;
        }
    }
}
int main() {
    int n;
    cin >> n;
    vector<long long> city(n+1);
    for(int i=1; i<=n; i++)
        cin >> city[i];
    long long final_res = 0;
    int i=0;
    long long money = 0;
    for(; i<n/10; i++)
    {
        res = INT32_MIN;
        vector<bool> used(5, false);
        backtracking(city, i*10, money, used, 0);
        if(res == INT32_MIN)
        {
            cout<<-1<<endl;
            break;
        }
        else{
            money = res;
        }
        
    }
    if(res != INT32_MIN)
    {
        if((i+1)*10 > n && i*10 < n)
        {
            res = INT32_MIN;
            vector<long long> city_part(city.begin()+i*10, city.end());
            vector<bool> used(5, false);
            backtracking(city, i*10, money, used, 0);
            if(res == INT32_MIN)
            {
                cout<<-1<<endl;
            }
            else
                money = res;
        }
        if(res != INT32_MIN)
            cout<<money<<endl;
    }
    


}


发表于 2025-03-22 10:33:15 回复(0)
这道题题目应该要说一句所有测试数据n都是10的倍数不然只能用记忆化收索加剪枝我的剪枝已经很好了但还是只能过16个
import java.util.*;
import java.io.*;
public class Main {
    public static final int MAXN=100001;
    public static long[][][] dp=new long[MAXN][16][2];
    public static long[][] dp1=new long[MAXN][16];
    public static int[] array=new int[MAXN];
    public static int n;
    //记忆化收索
    public static long dfs(int cur,int status,long worth){
        if(cur>n) return Integer.MIN_VALUE;
        if(cur==n&&worth+array[cur]>=0) return array[cur];
        if(worth+array[cur]<0) return Integer.MIN_VALUE;
        if(status==0) status=15;
        if(dp[cur][status][0]!=-2&&dp[cur][status][1]>=worth) return dp[cur][status][0];
        long ans=Integer.MIN_VALUE;
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<4;i++){
            if((status&(1<<i))!=0){
                if(array[cur+i+1]>=0) ans=Math.max(ans,dfs(cur+i+1,(status^(1<<i)),worth+array[cur]));
                else list.add(i);
            }
        }
        for(int i:list){
            ans=Math.max(ans,dfs(cur+i+1,(status^(1<<i)),worth+array[cur]));
        }
        list.clear();
        dp[cur][status][0]=ans==Integer.MIN_VALUE?Integer.MIN_VALUE:ans+array[cur];
        dp[cur][status][1]=worth;
        return dp[cur][status][0];
    }
    //动态规划版
    public static void dfs1(){
        for(int i=1;i<=n;i++){
            for(int j=0;j<=15;j++){
                long ans=Integer.MIN_VALUE;
                for(int k=0;k<4;k++){
                    if((j&(1<<k))==0&&i>k){
                        ans=Math.max(ans,dp1[i-k-1][(j|(1<<k))==15?0:(j|(1<<k))]);
                    }
                }
                if(ans+array[i]<0) dp1[i][j]=Integer.MIN_VALUE;
                else dp1[i][j]=ans+array[i];
                //System.out.println(i+" "+j+" "+dp1[i][j]);
            }
        }
    }
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
        n=Integer.parseInt(br.readLine());
        String[] str=br.readLine().split(" ");
        array[0]=0;
        for(int i=0;i<n;i++){
            array[i+1]=Integer.parseInt(str[i]);
        }
        for(long[][] P:dp){
            for(long[] P1:P){
                Arrays.fill(P1,-2);
            }
        }
        //dfs(0,15,0);
        dfs1();
        bw.write((dp1[n][0]==Integer.MIN_VALUE?-1:dp1[n][0])+"");
        bw.close();
        br.close();
    }
}
发表于 2025-02-19 00:12:18 回复(0)
public class BigRichGame {
    public static void main(String[] args) {
        int[] cityCoin = {-1, 2, 3, 4, -9, -9, -1, 3, -1, -1, 10, -1, 20};
        int result = getResult(cityCoin);
        if (result == Integer.MIN_VALUE) {
            System.out.println("没有合适的组合到达n城市");
        } else {
            System.out.println("最大金币值:" + result);
        }
    }


    //将数组拆分成很多个10步
    public static int getResult(int[] cityCoin) {
        int[] steps = {1, 2, 3, 4};
        int res = 0;
        int l = cityCoin.length - 1;
        int r = -1;
        while (r < l) {
            int n = Math.min(r + 10, l);
            LinkedList<Integer> roundStep = new LinkedList<>();
            int max = getGoldCoin(cityCoin, r, n, steps, r, roundStep);
            res += max;
            r += 10;
        }
        return res;
    }


    //每十步的最优解
    public static int getGoldCoin(int[] cityCoin, int r, int n, int[] steps, int start, LinkedList<Integer> roundStep) {
        //如果已经到达n城市则不需要再往前,直接返回我所有拿到的值
        if (r == n) {
            return cityCoin[n];
        }

        int max = Integer.MIN_VALUE;

        for (int step : steps) {
            int next = r + step;

            //如果大于n则直接结束
            if (next > n) {
                continue;
            }

            if (roundStep.contains(step)) {
                continue;
            }

            roundStep.add(step);

            int nextAns = getGoldCoin(cityCoin, next, n, steps, start, roundStep);
            int nowAns = r != start ? cityCoin[r] : 0;
            int ans = nextAns == Integer.MIN_VALUE ? Integer.MIN_VALUE : Math.max(max, nowAns + nextAns);
            max = Math.max(ans, max);
            roundStep.removeLast();
        }

        return max;
    }

}

发表于 2025-02-15 20:32:53 回复(0)
不知道为什么,只通过17/20个用例

package main

import (
	"fmt"
	"math"
)

func main() {
	var count int
	fmt.Scan(&count)
	var city = make([]int64, count)
	for i := 0; i < count; i++ {
		fmt.Scan(&city[i])
		if city[i] < -1000000000 || city[i] > 1000000000 {
			fmt.Println("error")
		}
	}
	var card = make(map[int]bool, 4)
	for i := 1; i <= 4; i++ {
		card[i] = true
	}
	var maxCoin int64
	var globalMaxCoin int64
	var coin int64
	step := -1
	maxCoin = 0
	globalMaxCoin = 0
	coin = 0
	for step < count - 2 {
		for i := 1; i <= 4; i++ {
			card[i] = false
			step = step + i
			coin += city[step]
			for j := 1; j <= 4; j++ {
				if card[j] == true {
					card[j] = false
					step = step + j
					coin += city[step]
					for k := 1; k <= 4; k++ {
						if card[k] == true {
							card[k] = false
							step = step + k
							coin += city[step]
							for l := 1; l <= 4; l++ {
								if card[l] == true {
									card[l] = false
									step = step + l
									coin += city[step]
									if coin > maxCoin {
										maxCoin = coin
									}
									card[l] = true
									coin -= city[step]
									step = step - l
								}
							}
							card[k] = true
							coin -= city[step]
							step = step - k
						}
					}
					card[j] = true
					coin -= city[step]
					step = step - j
				}
			}
			card[i] = true
			coin -= city[step]
			step = step - i
		}
		step = step + 10
		globalMaxCoin += maxCoin
		coin = 0
		maxCoin = -math.MaxInt64
	}
	if step == count - 1 {
		fmt.Println(globalMaxCoin)
		return
	}
	fmt.Println(-1)
}


发表于 2025-01-27 19:53:28 回复(0)
import sys

def fn(init_curr, numbers):
    l = [[0 for _ in range(4)] for _ in range(10)]
    l[0][0] = numbers[0] + init_curr
    l[1][1] = numbers[1] + init_curr
    l[2][2] = numbers[2] + init_curr
    l[3][3] = numbers[3] + init_curr

    l[2][0] = max(l[0][0], l[1][1]) + numbers[2] if max(l[0][0], l[1][1]) > 0 else -1

    l[3][0] = max(l[0][0], l[2][2]) + numbers[3] if max(l[0][0], l[2][2]) > 0 else -1

    l[4][0] = max(l[0][0], l[3][3]) + numbers[4] if max(l[0][0], l[3][3]) > 0 else -1

    l[4][1] = max(l[1][1], l[2][2]) + numbers[4] if max(l[1][1], l[2][2]) > 0 else -1
    l[5][0] = (
        max(l[4][1], l[3][0], l[2][0]) + numbers[5]
        if max(l[4][1], l[3][0], l[2][0]) > 0
        else -1
    )

    l[5][1] = max(l[1][1], l[3][3]) + numbers[5] if max(l[1][1], l[3][3]) > 0 else -1
    # [[0, 1, 3], [], [2, 3]],
    l[6][0] = (
        max(l[5][1], l[4][0], l[2][0]) + numbers[6]
        if max(l[5][1], l[4][0], l[2][0])
        else -1
    )
    l[6][2] = max(l[2][2], l[3][3]) + numbers[6] if max(l[2][2], l[3][3]) > 0 else -1
    #  [[0, 2, 3]],
    l[7][0] = (
        max(l[6][2], l[4][0], l[3][0]) + numbers[7]
        if max(l[6][2], l[4][0], l[3][0]) > 0
        else -1
    )
    # 1, 2, 3
    l[8][1] = (
        max(l[6][2], l[5][1], l[4][1]) + numbers[8]
        if max(l[6][2], l[5][1], l[4][1]) > 0
        else -1
    )
    l[9][0] = (
        max(l[8][1], l[7][0], l[6][0], l[5][0]) + numbers[9]
        if max(l[8][1], l[7][0], l[6][0], l[5][0]) > 0
        else -1
    )
    return l[9][0]

    # aaa_maps = [[0 for _ in range(4)] for _ in range(10)]


count = int(sys.stdin.readline())
numbers = sys.stdin.readline().split()
numbers = [int(val) for val in numbers]
numbers = numbers + ([0] * (10 - len(numbers) % 10) if len(numbers) % 10 > 0 else [])
lp = len(numbers) // 10
init_curr = 0
for l in range(lp):
    init_curr = fn(init_curr, numbers[l * 10 : l * 10 + 10])
    if init_curr < 0:
        break
print(init_curr if init_curr >= 0 else -1)
 
直接把状态转移方程写出来,效率嘎嘎快。
发表于 2025-01-08 14:39:16 回复(0)
由于题目限制只能用完4张牌后才能重开一轮,我们这里使用全排列+队列,用全排列枚举所有使用牌的顺序,如果合法再转移状态,如果进行一轮完后的状态合法我们需要放入队列继续去利用它,具体实现代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
typedef pair<int,int>PII;
typedef pair<int,__int128>PI;
typedef pair<double,double>PDD;
typedef pair<LL,LL>PLL;
typedef tuple<LL,LL,LL,LL>t4i;
typedef tuple<int,int,int>t3i;
const long double eps=1e-7;
const int inf=0x3f3f3f3f;
const long long INF=1e18;
const double pai=acos(-1.0);
const int mod=1e9+7;
const int N=1e5+10,M=2e6+10;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
//__builtin_popcountll(x)
LL dp[N],a[N];
int p[5];
void solve()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],dp[i]=-INF;
	dp[0]=0;
	queue<PLL>q;
	q.push({0,0});
	while(q.size()){
		auto [ps,nw]=q.front();q.pop();
		if(nw<dp[ps]) continue;
		for(int i=1;i<=4;i++) p[i]=i;
		do{
			LL pos=ps,now=nw;
			bool ok=true;
			for(int i=1;i<=4;i++){
				LL x=pos+p[i];
				if(x<=n&&now+a[x]>=0) dp[x]=max(dp[x],now+a[x]),pos=x,now+=a[x];
				else{
					ok=false;
					break;
				}
			}
			if(ok) q.push({pos,now});
		}while(next_permutation(p+1,p+5));
	}
	if(dp[n]>=0) printf("%lld\n",dp[n]);
	else printf("-1\n");
}
int main()
{
	ios::sync_with_stdio(0); 
    cin.tie(0);
    cout.tie(0);
    int tt;tt=1;
   	//cin>>tt;
    while(tt--){
        solve();
    }
    return 0;
}

发表于 2024-11-29 14:57:36 回复(0)
感觉美团的考试时间有点紧,第四题两次考试都没写完,只能在这里写一下题解了。题目说了1,2,3,4四个卡牌只能用完了才能刷新,也就是说无论怎么走,最后必定经过10的倍数的节点。因为无论1,2,3,4怎么排列他们和始终为10。也就是每10步存一次档,看这10步怎么走最优,然后从这个最优点出发,往后继续往后走10步,如果不足10步,那就推导最后几步能否走到终点(题目说了必须要到达这个格子的时候硬币为正才算成功)。
import java.util.Scanner;

public class Main {
    static long max=Integer.MIN_VALUE;
    static int[] step=new int[]{1,2,3,4};//走1 2 3 4步的卡牌
    public static void normoaltune(int start,long[] num,long coin,int steps,int[] flag){
        //往后走十步的所有可能情况 取最大值
        if (coin<0)
            return ;
        if (steps==4){
            max=Math.max(max,coin);
            return;
        }
        for (int i = 0; i < 4; i++) {//依次使用卡牌 获取到硬币
            if (flag[i]==0){//没有被使用过
                flag[i]=1;//标记为使用
                normoaltune(start+step[i],num,coin+num[start+step[i]],steps+1,flag);
                flag[i]=0;//回溯为未使用的状态
            }
        }
    }
    public static void lasttune(int start,int finalstep,long[] num,long coin,int[] flag){//最后几步路
        if (coin<0)//小于0 坠机
            return ;
        if (start>finalstep)//越过了 坠机
            return;

        if (start==finalstep){//到达终点 保存最大值
            max=Math.max(max,coin);
        }

        for (int i = 0; i < 4; i++) {
            if (flag[i]==0&&start+step[i]<=finalstep){//卡牌没有被使用过 这段代码类似于走10步的代码
                flag[i]=1;//标记为使用
                lasttune(start+step[i],finalstep,num,coin+num[start+step[i]],flag);
                flag[i]=0;//回溯为未使用的状态
            }
        }
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        long[] nums=new long[n+1];
        for (int i = 0; i < n; i++) {
            nums[i+1]=in.nextLong();
        }
        int nor=n/10;//完整的十步
        int last=n%10;//最后几步

        long coin=0;
        boolean isreach=false;
        for (int i = 0; i < nor; i++) {
            max=Integer.MIN_VALUE;//初始化为最小值
            int[] flag=new int[4];
            normoaltune(i*10,nums,coin,0,flag);//往后走十步
            coin=max;
            if (coin<0) {
                //到不了 寄了
                isreach=true;
                break;
            }
        }
        if (isreach){//到不了
            System.out.println(-1);
        }else{
            //能到
            if (last==0)//正好是10的倍数 那就不用走最后几步了
                System.out.println(coin);
            else {//否则要走最后几步
                max=Integer.MIN_VALUE;//初始化为最小值
                int[] flag=new int[4];
                lasttune(n-last,n,nums,coin,flag);
                coin=max;
                if (coin<0)//硬币为负 到不了终点
                    System.out.println(-1);
                else//为正就输出
                    System.out.println(coin);
            }
        }
    }
}



发表于 2024-09-12 00:33:48 回复(0)
状态压缩DP,dp[i][x]:表示到第i个数字,状态为x的最多金币数。
转移方程:dp[i][1101]  = max(dp[i - 1][1100] + a[i - 1],  dp[i - 3][1001] + a[i - 3], dp[i - 4][0101] + a[i - 4])  
注意点:当i为整10时,dp[i][0] = dp[i][1111]

#include <bits/stdc++.h>
using namespace std;
int t, n, k, x, a[100200];
long long dp[100200][20];

int main() {
    ios::sync_with_stdio(false);
    cout.tie(0), cin.tie(0);
    cin >> n;
    for (int i = 1;i <= n; i ++) { // 注意 while 处理多个 case
        cin >> a[i];
    }
    memset(dp, -1, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1;i <= n;i ++) {
        for (int x = 0;x < 16;x ++)
        {
            for (int j = 0;j < 4;j ++) {
                if (x >> j & 1 and i - j - 1 >= 0 and 0 <= dp[i - j - 1][x ^ (1 << j)] )
                { 
                    dp[i][x] = max(dp[i][x], dp[i - j - 1][x ^ (1 << j)] + a[i - j - 1]);
                }
            }
        }
        if (i % 10 == 0) {
            //cout << " ?" << endl;
            dp[i][0] = max(dp[i][0], dp[i][15]);
        }
    }
    //cout << dp[10][0] << " " << dp[10][15] << endl;

    long long ans = -1;
    for (int x = 0;x < 16;x ++)
    {
        //cout << dp[1][x] << endl;
        ans = max(ans, dp[n][x]);
    }
    if (~ ans)  ans += a[n];
    cout << (ans >= 0 ? ans : -1) << endl;
}
// 64 位输出请用 printf("%lld")

发表于 2024-08-21 18:04:43 回复(0)