题解 小L的有向图
挺思路的题,正解比暴力好写
对于 \(n\leqslant 9\):全排列枚举拓扑序,考虑排在前面的点向排在后面的点连出的边的状态可以任意,于是可以统计
然后正解:状压枚举拓扑序,考虑向一个已经确定的点集中加入一个点,则这个点向已经确定的点集中连出的边都一定不能选
而其它的可以任意,于是可以统计出加入一个点后的方案数,于是得解
- 拓扑序之类的东西是可以用转移顺序表示出来的(废话),可以借此完成一些对拓扑序有要求的DP
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
int cnt[N], head[N], size;
const ll mod=998244353;
struct edge{int to, next; bool vis;}e[N<<1];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
namespace force{
int tot;
ll ans;
bool vis[N];
void dfs(int u) {
if (u>n) {++ans; return ;}
for (int i=1; i<=n; ++i) if (!vis[i] && !cnt[i]) {
vis[i]=1;
for (int j=head[i],v; ~j; j=e[j].next) if (!e[j].vis) --cnt[e[j].to];
dfs(u+1);
for (int j=head[i],v; ~j; j=e[j].next) if (!e[j].vis) ++cnt[e[j].to];
vis[i]=0;
}
}
void solve() {
memset(head, -1, sizeof(head));
for (int i=1,x,y; i<=m; ++i) {
x=read(); y=read();
add(x, y);
++cnt[y];
}
int lim=1<<m;
for (int s=0; s<lim; ++s) {
// cout<<"s: "<<bitset<4>(s)<<endl;
for (int i=0; i<m; ++i) if (s&(1<<i)) e[i+1].vis=1, --cnt[e[i+1].to];
dfs(1);
for (int i=0; i<m; ++i) if (s&(1<<i)) e[i+1].vis=0, ++cnt[e[i+1].to];
// cout<<"ans: "<<ans<<endl;
}
printf("%lld\n", ans%mod);
exit(0);
}
}
namespace task{
ll dp[1<<22];
int cnt[30], out[N], siz[1<<22];
void solve() {
for (int i=1,x,y; i<=m; ++i) {
x=read()-1; y=read()-1;
++cnt[x]; out[x]|=1<<y;
}
int lim=1<<n;
for (int s=1,s2=1; s<lim; ++s,s2=s) do {++siz[s]; s2&=s2-1;} while (s2);
dp[0]=1;
for (int s=0; s<lim; ++s) {
for (int i=0; i<n; ++i) if (!(s&(1<<i))) {
dp[s|(1<<i)]=(dp[s|(1<<i)]+dp[s]*(1ll<<siz[out[i]&(~s)]))%mod;
}
}
printf("%lld\n", dp[lim-1]);
exit(0);
}
}
signed main()
{
freopen("topology.in", "r", stdin);
freopen("topology.out", "w", stdout);
n=read(); m=read();
// force::solve();
task::solve();
return 0;
}