题意:给定nnn个点mmm张图的有向图,有1∼m1\sim m1∼m互不相同每个点出度不超过kkk。对于一个 kkk元组cic_ici,图中的每个点uuu只保留第cdeguc_{deg_u}cdegu小的边。求有多少种ccc使得在保留下来的图中每个点沿着出边一直往下走可以走回自己。
n,m≤2×105,k≤9n,m\leq 2\times 10^5,k\leq 9n,m≤2×105,k≤9
显然直接k!k!k!暴力枚举方案,问题在于如何快速判断。
不难看出题中的条件等价于每个点入度恰好为111
也相当于每条边的终点恰好遍历1∼n1 \sim n1∼n
写个哈希就完了
复杂度O(n+k!)O(n+k!)O(n+k!)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <utility>
#include <cstdlib>
#include <ctime>
#define MAXN 200005
using namespace std;
int u[MAXN],v[MAXN],n,m,k;
typedef pair<int,int> pi;
vector<int> e[MAXN];
vector<pi> lis[MAXN];
inline int id(const pi& p){return p.first*(p.first-1)/2+p.second;}
int ans[10],key[MAXN],val[10][10],rt,cnt;
void check()
{int t=0;for (int i=1;i<=k;i++) t+=val[i][ans[i]];if (t==rt) ++cnt;
}
void dfs(int i)
{if (i>k) return check();for (ans[i]=1;ans[i]<=i;ans[i]++) dfs(i+1);
}
int main()
{scanf("%d%d%d",&n,&m,&k);for (int i=1;i<=n;i++) rt+=(key[i]=rand());for (int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);u[w]=x,v[w]=y;}for (int i=1;i<=m;i++) e[u[i]].push_back(v[i]);for (int u=1;u<=n;u++)for (int i=0;i<(int)e[u].size();i++)val[e[u].size()][i+1]+=key[e[u][i]];dfs(1);cout<<cnt;return 0;
}