[CF1394B] Boboniu Walks on Graph - hash
阿新 • • 發佈:2020-09-09
Description
給定有向圖,在圖上走的時候,出度為 \(i\) 的邊,只能走到邊權大小為第 \(c_i\) 小的邊上面,問 \(c\) 陣列有多少種,要每個點都滿足:從這個點開始走都可以回到這個點。每個點的入度都小於等於 \(9\)。
Solution
最終每個點一定只會有一個出點,將 \(p\) 的出度為 \(f[p]\),則顯然 \(f[]\) 一定是 \(1..n\) 的一個全排列
考慮到 \(f[]\) 的關於 \(c[]\) 的各個位是獨立的,因此可以分別列舉 \(c\) 的每一位,生成 \(f[]\) 的某些校驗值(組合),與全排列比較即可,校驗可以 hash,這裡為了省事,對每一位預先生成一個隨機數 \(w[]\)
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1000005; const int mod = 1e12+7; int n,m,k,a[N],w[N],c[N],ans,stdsum; struct edge { int v,w; bool operator < (const edge &obj) { return w < obj.w; } }; vector <edge> g[N]; vector <int> res[N]; vector <int> vec[N]; void dfs(int p,int sum) { //cout<<"dfs "<<p<<" "<<sum<<endl; if(p==k+1) { //cout<<sum<<","; if(sum==stdsum) ++ans; } else { for(int i:res[p]) { dfs(p+1,(sum+i)%mod); } } } signed main() { ios::sync_with_stdio(false); cin>>n>>m>>k; for(int i=1;i<=m;i++) { int t1,t2,t3; cin>>t1>>t2>>t3; g[t1].push_back({t2,t3}); } for(int i=1;i<=n;i++) { vec[g[i].size()].push_back(i); } for(int i=1;i<=n;i++) { sort(g[i].begin(),g[i].end()); } for(int i=1;i<=n;i++) { w[i]=rand()*rand(); stdsum+=w[i]; stdsum%=mod; } for(int pos=1;pos<=k;pos++) { for(int val=0;val<pos;val++) { int tmp=0; for(int i:vec[pos]) { tmp+=w[g[i][val].v]; } res[pos].push_back(tmp); } } for(int i=1;i<=k;i++) { if(res[i].size()==0) res[i].push_back(0); } dfs(1,0); cout<<ans<<endl; }