2024.11.9组队训练题解记录

Teleportation

鲍勃最近访问了一个奇怪的传送系统。该系统包含 \(n\) 个房间,编号为 \(0\)\(n-1\)。每个房间都安装了一个传送设备。每个传送设备都有一个看起来像钟表表面的仪表板,上面有一个指针,显示数字 \(0\)\(n-1\),按顺时针顺序排列。最初,第 \(i\) 个房间的传送设备上的指针指向数字 \(a_i\)

当鲍勃在房间 \(i\)\(0 \leq i \leq n-1\))时,他可以进行以下操作任意次数:

  • 传送:立即传送到房间 \((i + a_i) \mod n\)
  • 逆时针移动指针。设置 \(a_i \leftarrow a_i + 1\)
    每次操作需要一个时间单位。鲍勃从房间 \(0\) 开始,他想尽快到达某个房间 \(x\)。他想知道需要多长时间。
    \(Input\)
    输入的第一行包含两个整数 \(n\)\(2 \leq n \leq 10^5\))和 \(x\)\(1 \leq x \leq n - 1\)),分别表示房间的数量和鲍勃的目的地房间。
    下一行包含 \(n\) 个整数 \(a_0, a_1, \ldots, a_{n-1}\)\(0 \leq a_i \leq n - 1\)),其中 \(a_i\)\(0 \leq i \leq n - 1\))表示第 \(i\) 个房间的指针指向的数字。
    \(Output\)
    输出一个整数,表示鲍勃从房间 0 到达房间 \(x\) 所需的最短时间。

\(Sample1\)
4 3
0 1 2 3


4
\(Sample2\)
4 3
0 0 0 0


4
\(Sample3\)
4 3
2 2 2 2


2
思路:这题得转换一下,不然边要建太多了,不妨设1到n-1为本,n到\(2*n-1\)为真,对于本来讲,从1到n-1做有向边,从左指向右边(注意n-1->0也要),设立边费用为1;且对于每个数建立个零费用边到其对应的真边
随后就是i+a[i]了,建立对应i的真边i+n到(i+a[i])%n的本的单向边,且设立费用为1.
随后优先队列走一个最短路就行了,从n出发
从真点集出发一是可以直接到对应连接的本点,二是可以利用本点集中单向边的指向性质,一个有向环,实现费用转移优化。
这样子既合理有实现了边集大小的控制,即3*n,最后走一遍迪杰斯特拉就可得到答案
由于迪杰斯特拉本质就是最近扩散,所以当遇以目标点扩散时,其一定为最小值,这时可以直接break

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<cmath>
#include<string>
#define ll  long long 
#define lowbit(x) (x & -x)
#define endl "\n"
using namespace std;
vector<pair<ll,ll>>g[250000];
void fio()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}
bool vis[250000];
ll n,m;
ll ans=0;
void bfs()
{
    priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,greater<pair<ll,ll>>>q;
    q.push({0,n});
    while(!q.empty())
    {
        ll x=q.top().first;
        ll y=q.top().second;
        q.pop();
        if(vis[y])
        continue;
        vis[y]=1;
        if(y==m+n)
        {
            ans=x;
            break;
        }
        for(auto j:g[y])
        {
            q.push({x+j.first,j.second});
        }
    }
}
int main() 
{
	fio();
    cin>>n>>m;
    for(ll i=0;i<n;i++)
    {
        ll x;
        cin>>x;
        g[n+i].push_back({1,(x+i)%n});
    }
    for(ll i=0;i<n-1;i++)
    {
        g[i].push_back({1,i+1});
        g[i].push_back({0,i+n});
    }
    g[n-1].push_back({1,0});
    g[n-1].push_back({0,2*n-1});
    bfs();
    cout<<ans<<endl;
}
posted @ 2024-11-09 19:12  长皆  阅读(45)  评论(0编辑  收藏  举报