冒险者



题解

本蒟蒻采用的和大部分人解法不同,是根据当前标记值的总和跑最短路的一种解法。

思路 30min ,调代码 2h 的我太蒻了

首先观察题面可以发现本题求的是最少操作数,由于要求最小且有变化的过程,所以可以使用 dp 求解,也可以使用 最短路算法 求解,本篇先介绍最短路的算法。

其实作为图论来解还挺需要思维的。

最短路做法

建图

可以把本题抽象为以下的问题:

以编号为 \(\sum_{i = 1}^{n} a_i\) 的节点为起点,每次可以减去任何一个 \(a_i\) 并到达编号为这个数的节点,每个 \(a_i\) 最多可以减去一次;每次也可以加上一个 \(1\) 并到达编号为这个数的节点,有无限次数,任何边的权值都为 \(1\) ,求到达编号为 \(x\) 的倍数的节点的最短路。

实现

写题解的时候突然发现由于边权为 1 ,所以本题可以使用 bfs 用 \(O(n)\) 的时间进行求解,数据甚至可以更大一些。

但考试的时候没想那么多,就使用了 Dijkstra 算法,时间为 \(O(m \log m)\),由于边数可能比较多,因此不提前建出边来,而是对每个节点临时建边。看似复杂度很大,实际上有效边数并没有这么多,最大的数据也只跑了 13ms ,若用 bfs 可能会更少。

同时注意到每个数只能被减去一次,由于堆优化 dijkstra 的堆中每个情况是相对独立的,所以每个情况都要开额外的一个数组来存储每个数是否使用过,为了节省空间防止 MLE ,这里采用 bitset 来压缩空间。就是这里写错下标导致我调了 2h。

然后其他的就按照正常的最短路跑就行了。

代码

直接贺了赛时的 dijkstra 上去,什么时候有时间再来写 bfs 版和 dp 版的吧。

#include <bits/stdc++.h>
using namespace std;
int n,x;
int a[1005],start=0;
int dis[1001005];
bool vis[1001005];
struct node{
bitset<1005>bs;
int f,s;
}tmp,tmp2;
struct cmp{
bool operator()(node b,node c)
{
return c.f<b.f;
}
};
int dijkstra()
{
memset(dis,0x3f,sizeof(dis));
priority_queue<node,vector<node>,cmp> q;
tmp.f=0,tmp.s=start;
q.push(tmp);
dis[start]=0;
while(!q.empty())
{
tmp=q.top();
q.pop();
int oridis=tmp.f,u=tmp.s;
if(u%x==0)
{
return dis[u];
}
if(vis[u])continue;
vis[u]=1;
for(int i=1;i<=n;i++)
{
if(tmp.bs[i]==0)
{
int v=u-a[i];
if(dis[v]>oridis+1)
{
dis[v]=oridis+1;
tmp2.f=dis[v],tmp2.s=v;
tmp2.bs=tmp.bs;
tmp2.bs[i]=1;//就是这个下标坑我2h
q.push(tmp2);
}
}
}
int v=u+1;
if(v<=start+1000 && dis[v]>oridis+1)//最多操作次数为1000次
{
dis[v]=oridis+1;
tmp2.f=dis[v],tmp2.s=v;
tmp2.bs=tmp.bs;
q.push(tmp2);
}
}
return n;
}
int main()
{
freopen("player.in","r",stdin);
freopen("player.out","w",stdout);
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>a[i];
start+=a[i];
}
int res=dijkstra();
cout<<res;
return 0;
}

dp 做法

没有想到这个做法的原因主要还是最近 dp 有点生疏,一直往利用元素的条件来想,而忽视了靠元素的数值来解决问题。

这是典型的以数字设计 dp ,而不是用元素设计的一道题,从 \(a_i\le 1000\) 就可以看出。

同时,对于一个数删不删除,对应着 2 种状态,并且一旦知道删了哪些数,就可以推出这时要加多少个 1 。所以,就此设计转移方程式即可。

第一维是一个常见的 dp 设计思路:对于前 \(i\) 个数进行选择的结果,第二维是当前的数的总和 $sum \mod x $ 的结果。

于是,定义 \(f[i][j]\) 表示在前 \(i\) 个数中,使存在的数的总和 \(\mod x\) 为 \(j\) 时,最少删去的数的数量。

转移方程式为:\(f[i][j]=\min(f[i-1][j]+1,f[i-1][(j-a[i]+x)\mod x])\) ,其中 $ 1\le i\le n , 0\le j <x $。

最后计算答案时,直接输出 $\min(f[n][j]+(x-j)\mod x) , 0\le j <x $ 即可。

然后还要注意一点:初始化 \(f[0][0]=0\) 。

时间 \(O(nx)\) 。

未优化代码如下:

#include <bits/stdc++.h>
using namespace std;
int a[1005],n,f[1005][1005],x;
int main()
{
freopen("player.in","r",stdin);
freopen("player.out","w",stdout);
memset(f,0x3f,sizeof(f));
f[0][0]=0;
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]%=x;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<x;j++)
{
f[i][j]=min(f[i-1][j]+1,f[i-1][(j-a[i]+x)%x]);
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<x;i++)
{
ans=min(ans,f[n][i]+(x-i)%x);
}
cout<<ans;
return 0;
}

优化

注意到动态转移方程式的第一维只会用到 \(i-1\) 的值,所以可以强行进行滚动数组优化,虽然不这样做也可以过就是了。

滚动数组优化代码:

#include <bits/stdc++.h>
using namespace std;
int a[1005],n,f[2][1005],x;
int main()
{
freopen("player.in","r",stdin);
freopen("player.out","w",stdout);
memset(f,0x3f,sizeof(f));
f[0][0]=0;
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]%=x;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<x;j++)
{
f[i&1][j]=min(f[(i&1)^1][j]+1,f[(i&1)^1][(j-a[i]+x)%x]);//i&1=i%2,(i&1)^1=(i+1)%2
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<x;i++)
{
ans=min(ans,f[n&1][i]+(x-i)%x);
}
cout<<ans;
return 0;
}

Hetao P1178 冒险者 题解 [ 绿 ][ 最短路 ][ 线性 dp ]的更多相关文章

  1. [luogu1772 ZJOI2006] 物流运输 (最短路 线性dp)

    题目描述 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪. ...

  2. 【NOI2005】聪聪与可可 题解(最短路+期望DP)

    前言:学长讲的太神了:自己还能推出来DP式子,挺开心. -------------------------- 题目链接 题目大意:给定一张含有$n$个结点$m$条边的无向连通图.现在聪聪在点$s$,可 ...

  3. 【题解】LOJ6060 Set(线性基)

    [题解]LOJ6060 Set(线性基) orz gql 设所有数的异或和为\(S\),答案是在\(\max (x_1+S\and x_1)\)的前提下\(\min x_1\)输出\(x_1\) 转换 ...

  4. Codeforces 176B (线性DP+字符串)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  5. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

  6. 【洛谷P1854】花店橱窗 线性dp+路径输出

    题目大意:给定 N 个数字,编号分别从 1 - N,M 个位置,N 个数字按照相对大小顺序放在 M 个位置里,每个数放在每个位置上有一个对答案的贡献值,求一种摆放方式使得贡献值最大. 题解:一道典型的 ...

  7. 线性dp

    线性dp应该是dp中比较简单的一类,不过也有难的.(矩乘优化递推请出门右转) 线性dp一般是用前面的状态去推后面的,也有用后面往前面推的,这时候把循环顺序倒一倒就行了.如果有的题又要从前往后推又要从后 ...

  8. [CodeForces - 1272D] Remove One Element 【线性dp】

    [CodeForces - 1272D] Remove One Element [线性dp] 标签:题解 codeforces题解 dp 线性dp 题目描述 Time limit 2000 ms Me ...

  9. 【题解】NOIP2017逛公园(DP)

    [题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n​节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...

  10. 非常完整的线性DP及记忆化搜索讲义

    基础概念 我们之前的课程当中接触了最基础的动态规划. 动态规划最重要的就是找到一个状态和状态转移方程. 除此之外,动态规划问题分析中还有一些重要性质,如:重叠子问题.最优子结构.无后效性等. 最优子结 ...

随机推荐

  1. Django之gunicorn部署

    安装: pip install gunicorn 启动应用: gunicorn -w 3 -k gthread -e DJANGO_SETTINGS_MODULE=settings.prod Serv ...

  2. px2rem 实现vue rem 自适应/

    npm install postcss-px2rem px2rem-loader --save 新建js 文件rem.js // rem等比适配配置文件 // 基准大小 const baseSize ...

  3. 【Kotlin】select简介

    1 前言 ​ 协程的 select 是一种用于异步操作的选择器,它允许同时等待多个挂起函数的结果,并在其中一个完成时执行相应的操作. ​ 能够被 select 的事件都是 SelectClause,在 ...

  4. PM-数据治理-数据资产管理

      在组织中,并非所有的数据都构成数据资产,数据资产是能够为组织产生价值的数据,数据资产的形成需要对数据进行主动管理并形成有效控制.   数据资产管理是规划.控制和提供数据及信息资产的一组业务职能,包 ...

  5. WinDbg: Failed to find runtime module (coreclr.dll or clr.dll or libcoreclr.so)

    当我们通过 WinDbg 启动一个 .NET 的程序时,WinDbg 将会在运行可执行之前执行一个中断,此时还没有加载 .NET 的运行时. 但是,SOS 扩展需要 clr.dll 或者 corecl ...

  6. Redis应用—8.相关的缓存框架

    大纲 1.Ehcache缓存框架 (1)Ehcache的核心对象 (2)单独使用Ehcache (3)Spring整合Ehcache (4)Spring Boot整合Ehcache (5)实际工作中如 ...

  7. Qt/C++地图高级绘图/指定唯一标识添加删除修改/动态显示和隐藏/支持天地图高德地图百度地图

    一.前言说明 已经有了最基础的接口用来添加覆盖物,而且还有通过进入覆盖物模式动态添加覆盖物的功能,为什么还要来个高级绘图?因为又有新的需求,给钱就搞,一点底线都没有.无论哪个地图厂家,提供的接口都是没 ...

  8. Uniapp 获取当前版本号

    plus.runtime.getProperty(plus.runtime.appid, function(wgtinfo) { oldversion = wgtinfo.versionCode // ...

  9. springboot的yml文件中如何配置redis?

    springboot的yml文件中如何配置redis? 解决方法: spring: #redis配置 redis: database: 0 timeout: 0 # Redis服务器地址 host: ...

  10. 记录uniapp上传图片转base64

    // 图片转base64 imageToBase64() { return new Promise((reslove, reject) => { uni.getFileSystemManager ...