首页 > 其他分享 >YACS 2023年2月月赛 甲组 T1 自由贸易 题解

YACS 2023年2月月赛 甲组 T1 自由贸易 题解

时间:2023-02-18 09:33:50浏览次数:62  
标签:YACS 分数 水果 int 题解 甲组 ++ 常数

题目链接

上来一看题和数据范围基本就是 DP 了,问题是状态怎么设计呢?

如果我们仅仅设 $f[i]$ 为到第 $i$ 个水果时的最大分数,那么显然会发现无法处理当前水果的分数贡献。

再来想一想我们 $DP$ 的目的是什么呢?压缩状态,去除冗余。如果我们需要统计当前水果的分数贡献,那么就需要上两次的水果是什么,状态就出来了。

$f[i][j][k][l][m]$ 为到第 $i$ 个水果时,上两个给南极的是 $j$,$k$。没有则为 $0$。上两个给北极的是 $l$,$m$ 时的最大分数,发现转移方程仍然不是很好写,考虑贡献转移法。

如果 $f[i][j][k][l][m]$ 是可行的,那么第 $i + 1$ 个水果给南极和北极都可以,两个都给下取个最值就行。

如果算到 $n - 1$ 了,那么算好 $n$ 后直接给 $ans$ 取最值就行了。

常数非常大,$64$,总共复杂度 $O(64\times n)$,手算发现超过 $1e8$ 一点点。为了避免机器故意跑的太慢,或者数据太毒瘤,我们需要进行常数优化。

可以发现:$f[i][j][k][l][m]$ 中的 $j$ 和 $k$ 以及 $l$ 和 $m$ 是没有顺序要求的,把 $j$ 和 $k$ 颠倒过来也没什么事,统计答案过程是一样的。

所以循环的时候前面小于后面,优化掉一个 $4$ 的常数,可惜我懒就算了吧。

最终时间复杂度 $O(16\times n)$,常数太大了,所以我还是把它放进来吧。

(甲组 T2 T3,太水了,不写了)

代码:

#include <cstring>
#include <iostream>
using namespace std;
int n, ans, a[200005], b[10];
int f[200005][4][4][4][4];
void ma (int &a, int b) {if (a < b) a = b;}
int main () {
    cin >> n;
    for (int i = 0; i < n; i ++) for (int j = 0; j < 4; j ++) for (int k = 0; k < 4; k ++) for (int l = 0; l < 4; l ++) for (int m = 0; m < 4; m ++) f[i][j][k][l][m] = -1000000000;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    f[0][0][0][0][0] = 0;
    for (int i = 0; i < n; i ++) for (int j = 0; j < 4; j ++) {
        for (int k = 0; k < 4; k ++) for (int l = 0; l < 4; l ++) {
            for (int m = 0; m < 4; m ++) if (f[i][j][k][l][m] >= 0) {
                int sum = 0;
                b[1] = b[2] = b[3] = 0;
                ++ b[j]; ++ b[k]; ++ b[a[i + 1] ];
                for (int t = 1; t <= 3; t ++) if (b[t]) ++ sum;
                ma (f[i + 1][k][a[i + 1] ][l][m], f[i][j][k][l][m] + sum);
                sum = 0; b[1] = b[2] = b[3] = 0;
                ++ b[l]; ++ b[m]; ++ b[a[i + 1] ];
                for (int t = 1; t <= 3; t ++) if (b[t]) ++ sum;
                ma (f[i + 1][j][k][m][a[i + 1] ], f[i][j][k][l][m] + sum);
            }
        }
    }
    for (int i = 0; i < 4; i ++) for (int j = 0; j < 4; j ++) {
        for (int k = 0; k < 4; k ++) for (int l = 0; l < 4; l ++) {
            ans = max (ans, f[n][i][j][k][l]);
        }
    }
    cout << ans;
    return 0;
}

 

标签:YACS,分数,水果,int,题解,甲组,++,常数
From: https://www.cnblogs.com/Xy-top/p/17131977.html

相关文章

  • ARC111C Too Heavy 题解
    无解的情况:当且仅当一个人手上的物品不是自己的物品,并且这个物品的质量大于自己的体重,这个不是自己的东西就卡手了,换不出去,无解。甲手上是乙的物品。乙的手上是丙的物品,丙......
  • NOIP2022 简要题解
    前言作为一名退役OIer,借着此比赛来复健。大部分题目都是口胡(没啥好写的),spj题手写了代码,A了。难度不算特别高,但是赛场上拿到高分略有压力(退役了可以瞎bb)。个人认为应该......
  • 题解 CF690C2
    题目大意:给你一棵树,求一下直径题目分析:emm,怎么说吧,就是树的直径的裸板子。可能有人不大理解,明明是图,你为什么要说是给定一棵树。大家可以自行验证一下,满足如下两个性......
  • 题解 CF690C1
    题目大意:给定一张\(n\)个点\(m\)条边的无向图,判断这是不是一棵树。题目分析:两种思路:思路一:不需要建图,直接使用并查集判环即可最后判断一下图联不联通就行,具体方......
  • 一个autoreconf的报错问题解决
    报错如下configure.ac:36:error:possiblyundefinedmacro:AC_CHECK_LIBIfthistokenandothersarelegitimate,pleaseusem4_pattern_allow.Seet......
  • 题解 CF637B
    题目大意:维护个栈,去重保留最上层题目分析:啥也不是,数组模拟\(\text{stack}+\text{unordered\_map}\)直接秒掉。复杂度\(O(n)\)代码实现:#include<bits/stdc++.h>......
  • 题解 CF742B
    题目大意:给定\(n\)个数,找数对使其异或值为\(k\),求满足这样数对的个数。题目分析:考验位运算功底的题目(实际上也不是很难),主要运用到了下列性质:\[\begin{aligned}\bec......
  • 20230207模拟赛题解
    A-CF755D考虑每次加边产生的贡献。发现每次加边的贡献是这条边与别的边的交点数量加\(1\)。所以可以用线段树或树状数组等数据结构维护,注意要令\(k=\min(k,n-k)\)。B-......
  • CAD坐标显示不全怎么办?CAD坐标常见问题解答!
    今天小编来和大家聊一下浩辰CAD看图王中关于CAD坐标的那些事,比如:CAD坐标为何显示不全?CAD坐标显示结果和之前不一样?以及不能精准捕捉CAD坐标等情况,应该如何轻松解决?今天就和......
  • 0210 模拟题解
    0210模拟题解t1直接枚举\(k\),考虑计算答案。首先发现这个限制等价于存在长度\(\gen-k\)的上升子段。那我们反过来,计算所有上升子段长度都\(\len-k-1\)的方案数......