题解:P12639 [UOI 2020] Topological Sorting of a Tree
UOI 怎么考板子题??经典树上拓扑序容斥。
将填入数字看成拓扑序,如果全部都是
现在我们多了内向边,于是需要把他们容斥掉。假设钦定了
考虑带着容斥系数进行 dp,每钦定一条边就
由于贡献系数是和子树大小相关的,所以我们要在 dp 的时候记录当前联通块的大小。所有设
在遇到
在遇到
注意每次做完转移之后要
时间复杂度
#include<bits/stdc++.h>
#define pb emplace_back
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
const int maxn=3e3+10;
const int mod=1e9+7;
void add(int &x,int y){ x=x+y>=mod?x+y-mod:x+y; }
void sub(int &x,int y){ x=x<y?x-y+mod:x-y; }
vector<pair<int,int> > G[maxn];
int n,f[maxn][maxn],g[maxn],sz[maxn];
int C[maxn][maxn],inv[maxn],fac[maxn];
void dfs(int u,int fa){
f[u][1]=1; sz[u]=1;
for(auto z:G[u]){
int v=z.fi,w=z.se;
dfs(v,u);
if(w){
for(int i=1;i<=sz[u];i++)
for(int j=1;j<=sz[v];j++)
add(g[i+j],1ll*f[u][i]*f[v][j]%mod*C[sz[u]+sz[v]][sz[u]]%mod);
}else{
for(int i=1;i<=sz[u];i++)
for(int j=1;j<=sz[v];j++){
sub(g[i+j],1ll*f[u][i]*f[v][j]%mod*C[sz[u]+sz[v]][sz[u]]%mod);
add(g[i],1ll*f[u][i]*f[v][j]%mod*C[sz[u]+sz[v]][sz[u]]%mod);
}
}
sz[u]+=sz[v];
for(int i=1;i<=sz[u];i++) f[u][i]=g[i],g[i]=0;
}
for(int i=1;i<=sz[u];i++) f[u][i]=1ll*f[u][i]*inv[i]%mod;
}
void init(){
inv[1]=fac[0]=1; C[0][0]=1;
for(int i=1;i<=n;i++) fac[i]=1ll*i*fac[i-1]%mod;
for(int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n; init();
for(int v=2;v<=n;v++){
int u,t=0; char ch;
cin>>u>>ch; t^=(ch=='<');
G[u].pb(v,t);
}
dfs(1,0); int ans=0;
for(int i=1;i<=n;i++) add(ans,f[1][i]);
cout<<ans<<endl;
return 0;
}