題解:AT_abc372_f [ABC372F] Teleporting Takahashi 2

WuMin4發表於2024-09-22

題意

給出一個 \(n\) 個點的有向圖,點 \(i\) 連向點 \((i+1)\),點 \(n\) 連向點 \(1\)。再給你 \(m\) 條額外邊。你的初始位置為 \(1\),問你移動 \(k\) 步的不同方案數(僅當路徑不同時兩個方案不同)。

思路

先想怎樣暴力轉移,顯然移動 \(k\) 步到達一個點的方案數為所有跟這個點連邊的移動 \((k-1)\) 步到達的點的方案數的總和,時間複雜度 \(O((n+m)k)\),顯然不能接受。
可以發現 \(m\le 50\),考慮最佳化掉 \(n\)。最開始的 \(n\) 條初始邊構成了一個環,所以每個點 \(i\) 都一定會從 \((i-1)\) 轉移過來,也就是環上的數整體右移一位。我們換位思考,不去右移環上的數,而是整體左移一位額外邊上的數,時間複雜度就會大大減小了。因為最外圈是個環,所以整體左移額外邊雖然會改變連邊關係,但是不會改變邊的相對位置,對答案不會造成影響。時間複雜度 \(O(mk)\),可以透過。

程式碼

#include<bits/stdc++.h>
#define md 998244353
using namespace std;
int n,m,k,num[200005],ANS;
vector<int> t[200005],pt;
int to(int x,int i){//將點x左移i位,注意取模
	return ((x-i-1)%n+n)%n+1;
}
signed main(){
	cin>>n>>m>>k;
	num[1]=1;
	for(int x,y,i=1;i<=m;i++){
		cin>>x>>y;
		if(!t[x].size())
			pt.push_back(x);
		t[x].push_back(y);
	}
	for(int i=0;i<k;i++){//這裡先從額外邊轉移再整體左移,所以i從0開始
		vector<pair<int,int>> cge;
		for(int v:pt)
			for(int v2:t[v])
				cge.push_back({num[to(v,i)],to(v2,i+1)});//因為整體左移,所以從原來的u->v變為了u->(v-1)
		for(pair<int,int> v:cge)
			num[v.second]=(1ll*num[v.second]+v.first)%md;
	}
	for(int i=1;i<=n;i++)
		ANS=(ANS+num[i])%md;
	cout<<ANS;
	return 0;
}

相關文章