首页 > 其他分享 > [NOIP2010 提高组] 乌龟棋

[NOIP2010 提高组] 乌龟棋

时间:2023-10-16 15:22:32浏览次数:38  
标签:分数 顺序 卡片 格子 NOIP2010 爬行 乌龟 提高

题目背景

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

题目描述

乌龟棋的棋盘是一行 NN 个格子,每个格子上一个分数(非负整数)。棋盘第 11 格是唯一的起点,第 NN 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中 MM 张爬行卡片,分成 44 种不同的类型(MM 张卡片中不一定包含所有 44 种类型的卡片,见样例),每种类型的卡片上分别标有 1,2,3,41,2,3,4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

输入格式

每行中两个数之间用一个空格隔开。

第 11 行 22 个正整数 N,MN,M,分别表示棋盘格子数和爬行卡片数。

第 22 行 NN 个非负整数,a1,a2,…,aNa1​,a2​,…,aN​,其中 aiai​ 表示棋盘第 ii 个格子上的分数。

第 33 行 MM 个整数,b1,b2,…,bMb1​,b2​,…,bM​,表示 MM 张爬行卡片上的数字。

输入数据保证到达终点时刚好用光MM张爬行卡片。

输出格式

11 个整数,表示小明最多能得到的分数。

输入输出样例

输入 #1
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出 #1
73

说明/提示

每个测试点 1s。

小明使用爬行卡片顺序为 1,1,3,1,21,1,3,1,2,得到的分数为 6+10+14+8+18+17=736+10+14+8+18+17=73。注意,由于起点是 11,所以自动获得第 11 格的分数 66。

对于 30%30% 的数据有 1≤N≤30,1≤M≤121≤N≤30,1≤M≤12。

对于 50%50% 的数据有 1≤N≤120,1≤M≤501≤N≤120,1≤M≤50,且 44 种爬行卡片,每种卡片的张数不会超过 2020。

对于 100%100% 的数据有 1≤N≤350,1≤M≤1201≤N≤350,1≤M≤120,且 44 种爬行卡片,每种卡片的张数不会超过 4040;0≤ai≤100,1≤i≤N,1≤bi≤4,1≤i≤M0≤ai​≤100,1≤i≤N,1≤bi​≤4,1≤i≤M。

一看到这个,就感觉和背包很像,于是就随手写了一个错的。。
大概是f[i][j]表示已经考虑到了第i个牌,然后当前走到了第j个格子。。
问题就是,这个解法是背包的,背包不考虑物品放入的顺序,这对他没有意义。。
这个要考虑,如果第i个牌暂时没有用,我们选择将它跳过,但是之后在想用的时候,我们是做不到的
所以顺序必要的时候,这种状态是完全处理不了的。

要考虑换一种做法
我们发现对于这个题目,有一个奇怪的条件,就是每一步的卡片数量是确定的
那我们其实可以直接把卡片数量记录下来啊
设f[i][j][k][h]表示用了i张走一步的卡片,j张走两步的牌,k张走3步的,走到了第h格的最大得分
看到这个状态,这题就出来了。。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
    char c=getchar();int a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int f[41][41][41][41],n,m,a[351],b[5];
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
    }
    for(int i=1;i<=m;i++)
    {
        b[read()]++;
    }
    f[0][0][0][0]=a[1];
    for(int i=0;i<=b[1];i++)
    {
        for(int j=0;j<=b[2];j++)
        {
            for(int k=0;k<=b[3];k++)
            {
                for(int h=0;h<=b[4];h++)
                {
                    int step=1+i+j*2+k*3+h*4;
                    if(i!=0)
                        f[i][j][k][h]=max(f[i][j][k][h],f[i-1][j][k][h]+a[step]);
                    if(j!=0)
                        f[i][j][k][h]=max(f[i][j][k][h],f[i][j-1][k][h]+a[step]);
                    if(k!=0)
                        f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k-1][h]+a[step]);
                    if(h!=0)
                        f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k][h-1]+a[step]);
                        
                }
            }
        }
    }
    cout<<f[b[1]][b[2]][b[3]][b[4]]<<endl;
    return 0;
}

这题主要是可以学习到一种关于顺序的dp
虽然这题中有每种牌类型的限制的条件,但是这种思路是值得学习的,特别是关于状态的设计
可以说是把原本需要枚举全排列的问题完美的解决了

因为我们其实是不关注前面的牌是怎么排列的,前面怎么排列其实对于后面的决策可以说是完全没有一点点影响
唯一的可以说是影响后面的只有答案,这还是对后面的决策没有影响(有影响还怎么dp。。

和顺序有关的题目,经典的就是路径问题
就像是之前那个传纸条,我们一直向着右下走,其实也是一样决定了前面的路径和后面的决策没有联系,而对后面决策有影响的“位置”被我们给放进了状态之中

也许我可以得出一个不坚固的结论,就是和顺序有关的题目,除了状压,我们能够做的就是尽量不去关注前面的路径,而是专注于我们目前所在的位置,或者说是状态能够记录的
否则没法做。。。

标签:分数,顺序,卡片,格子,NOIP2010,爬行,乌龟,提高
From: https://www.cnblogs.com/HLZZPawa/p/17766080.html

相关文章

  • P1019 [NOIP2000 提高组] 单词接龙
    P1019[NOIP2000提高组]单词接龙注意:1.相邻不包含2.每个单词最多使用两次3.如果两部分可以接龙,直接退出,因为如果再继续,长度一定变短(因为相邻的会抵销)4.加个特殊字符,这样就可以不用特判了因为n很小,直接暴力枚举1.如果两个可以接龙直接合并(注意相邻相同要抵消)2.暴力枚举每个单......
  • 牛客集训营提高组第二组第一题
    题目描述:链接:https://ac.nowcoder.com/acm/contest/65193/A给定正整数n,计算n 个元素的集合{1,2,⋯ ,n}所有非空子集和的乘积取模998 244 353998后的结果。n≤200。解题思路,n小于等于200并且子集所有的取值为n^2级别的,考虑跑背包,f[i]表示子集和为i的方案数,可以算出子集和......
  • 潍坊一中 2023 秋提高级友好学校赛前联测 1 T3
    Mystia的居酒屋题目背景小麻雀Mystia开了一间居酒屋,每天清晨她都要跨过门前的河流去收集食材。题目描述Mystia想搭一座跨过河的桥,来方便她取得食材。河是一条无限长的宽度为\(W\)的直线,所有在坐标系中符合\(0≤y≤W\)的点都属于这条河流。河面上有\(N\)个木桩,附......
  • P1967 [NOIP2013 提高组] 货车运输 (生成树,LCA)
    P1967[NOIP2013提高组]货车运输https://www.luogu.com.cn/problem/P1967首先有些边是没用的(比较小的边),比如两个点之间的两条(并行的)路,只有较大的会被走到,小的不会被走,因此可以直接去除小的边,即求最大生成树。接着做求任意两点经过的边的最小值就演变成求树上任意两点的最小树......
  • 标准工时制度通过多种方式提高生产效率
    标准工时制度在现代企业管理中扮演着重要的角色,它可以通过多种方式提高生产效率。在如今竞争激烈的市场环境下,企业需要持续提高运营效率以保持竞争力。以下是标准工时制度提高生产效率的一些主要途径:首先,标准工时制度可以帮助企业更准确地预测生产需求。通过对历史数据和市场趋势......
  • sql数据库怎么用:如何使用SQL数据库来提高业务效率
    SQL数据库是一种关系型数据库,它使用StructuredQueryLanguage(SQL)来存储、组织和检索数据。它可以被用来创建、修改和管理数据库中的表和数据。SQL数据库是一种关系型数据库,它使用StructuredQueryLanguage(SQL)来存储、组织和检索数据。它可以被用来创建、修改和管理数据库中的表和......
  • 23 年牛客提高组模拟赛 Day5 T3
    给你一个长为\(n\)的数组\(b_i\)表示原数组\(a_i\)中以\(i\)结尾的LIS长度,问对于所有\(1\leqa_i\leqm\),原数组有多少种不同的可能\(n\leq20,m\leq3000\)看到数据范围容易想到状压dp,赛事想了个比较朴素的dp:设\(dp_{S,i}\)表示填了集合\(S\)的数,其......
  • 如何提高爬虫IP时效,解决被封IP的问题呢?
    随着互联网的普及,越来越多的人开始使用爬虫技术来获取各种信息。然而,爬虫技术的发展也带来了一些问题,其中最突出的问题就是IP被封禁。那么,如何提高爬虫IP时效,解决被封IP的问题呢?首先,我们需要了解为什么会被封禁。一般来说,爬虫被封禁的原因主要有两个:一是访问频率过高,二是访问目标站......
  • 【日常收支账本】【Day05】编辑账本界面增加删除、更新记录功能——提高代码复用性
    一、项目地址https://github.com/LinFeng-BingYi/DailyAccountBook二、新增1.增加删除记录功能1.1功能详述点击删除按钮后,获取对应行的数据组成字典,用字典的键值对匹配到对应日期的记录元素;接着用该字典数据冲正存款账户余额(实现思路为新增记录时的反向操作),同时删除记录......
  • 牛客提高模拟赛第四场 T3
    给你一个数\(n\),让你从\(n\)中取出若干数合并成\(x\),剩下数合并成\(y\),求对于所有取法\(x+y\)的和例如\(12345\)可以拿出\(24\),剩下\(135\),此时会对答案产生\(24+135\)的贡献。而\(42,153\)或\(23,15\)是不合法的\(n\leq10^{10^5}\)显然\(\sumx......