2024.11.9組隊訓練題解記錄

长皆發表於2024-11-09

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;
}

相關文章