zoukankan      html  css  js  c++  java
  • P4099 [HEOI2013]SAO

    题解

    感觉是一道树型 ( ext{dp}) 好题,反正不看题解不会做,我真屑。

    题意很简单,给你一张有向树型图,问你拓扑序数量。

    因为我们发现如果一棵子树的内部的拓扑序已经确定了,影响这个子树与外面的相对关系的只有根节点,所以我们定义 (f_{i,j})(i) 在以 (i) 为根的子树中拓扑序位置为 (j) 的方案数。

    然后有了这个东西之后我们发现转移就很简单了。

    (u<v) ,则:

    [(new)f_{u,k}=inom{k-1}{i-1}inom{size_u+size_v-k}{size_u-i}cdot f_{u,i}sum_{j=k-i+1}^{size_v}f_{v,j} ]

    (u>v) ,则:

    [(new)f_{u,k}=inom{k-1}{i-1}inom{size_u+size_v-k}{size_u-i}cdot f_{u,i}sum_{j=1}^{k-i}f_{v,j} ]

    好像做完了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1e3+5;
    const int MOD=1e9+7;
    int n,siz[N];
    int f[N][N],g[N][N],h[N];
    int frac[N],ifrac[N];
    int ksm(int x,int k){
    	int res=1;
    	for(;k;k>>=1,x=x*x%MOD)
    	if(k&1) res=res*x%MOD;
    	return res;
    }
    int cal(int n,int m){
    	if(n<0||m<0||n<m) return 0;
    	return frac[n]*ifrac[m]%MOD*ifrac[n-m]%MOD;
    }
    struct Edge{int nxt,to,flag;}e[N<<1];int fir[N];
    void add(int u,int v,int w,int i){e[i]=(Edge){fir[u],v,w},fir[u]=i;}
    void dp(int u,int fa){
    	siz[u]=1,f[u][1]=1;
    	for(int i=fir[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa) continue;
    		dp(v,u),memset(h,0,sizeof(h));
    		for(int c=1;c<=siz[u];++c){
    			for(int d=1;d<=siz[u]+siz[v];++d){
    				if(e[i].flag){
    					if(d-c+1>siz[v]) continue;
    					h[d]+=cal(d-1,c-1)*cal(siz[u]+siz[v]-d,siz[u]-c)%MOD*f[u][c]%MOD*(g[v][siz[v]]-g[v][d-c]+MOD)%MOD;
    					h[d]%=MOD;
    				}
    				else{
    					if(1>d-c) continue;
    					h[d]+=cal(d-1,c-1)*cal(siz[u]+siz[v]-d,siz[u]-c)%MOD*f[u][c]%MOD*(g[v][d-c]-g[v][0]+MOD)%MOD;
    					h[d]%=MOD;
    				}
    			}
    		}
    		siz[u]+=siz[v];
    		for(int j=1;j<=siz[u];++j) f[u][j]=h[j];
    	}
    	// printf("%lld
    ",u);
    	// for(int i=1;i<=siz[u];++i) printf("%lld ",f[u][i]);
    	// printf("
    ");
    	for(int i=1;i<=siz[u];++i){
    		g[u][i]=(g[u][i-1]+f[u][i])%MOD;
    	}
    }
    void solve(){
    	cin>>n;
    	for(int i=1;i<n;++i){
    		int u,v;char s[2];
    		scanf("%lld%s%lld",&u,s,&v),u++,v++;
    		add(u,v,s[0]=='<',i<<1);
    		add(v,u,s[0]=='>',i<<1|1);
    	}
    	dp(1,0);
    	int res=0;
    	for(int i=1;i<=n;++i) res+=f[1][i],res%=MOD;
    	return printf("%lld
    ",res),void();
    }
    void init(){
    	memset(fir,0,sizeof(fir));
    	memset(g,0,sizeof(g));
    }
    signed main(){
    	frac[0]=1;
    	for(int i=1;i<N;++i) frac[i]=frac[i-1]*i%MOD;
    	ifrac[N-1]=ksm(frac[N-1],MOD-2);
    	for(int i=N-1;i>=1;--i) ifrac[i-1]=ifrac[i]*i%MOD;
    	int T;cin>>T;
    	while(T--) init(),solve();
    }
    
  • 相关阅读:
    Enhancing State-of-the-art Classifiers with API Semantics to Detect Evolved Android Malware论文阅读笔记
    this和super的总结
    软件工程结对WordCount项目
    软工个人作业 数独
    问题
    自我介绍
    shuduku
    access to DeepLearning
    自我介绍
    学习软工基目标
  • 原文地址:https://www.cnblogs.com/Point-King/p/14671103.html
Copyright © 2011-2022 走看看