HDU 5789 Permutation
来源:互联网 发布:python调用caffe测试 编辑:程序博客网 时间:2024/06/11 04:50
给定一棵大小为n的有根树,点的标号为1,…,n。现在要把树转化成一个序列,要求一个点的后代在序列中先出现,求所有满足条件的序列的逆序对数之和。
n≤50
定义子树对应的序列为副序列,已合并的子树对应的序列为主序列。
主序列的长度为
每次把主序列和副序列合并得到新的主序列
首先两个序列内部的逆序对数之和随着合并后总方案数增多而增多
令
方便起见,我们可以只枚举副序列中的元素
令
令
令
令
计算贡献的复杂度为
合并也是类似的,不过不同的是在计算贡献的时候两边的序列相当于确定了,所以组合数乘一下就好了,合并的时候只是把一个序列安置到一个新序列中,所以还要乘上另一个序列总的方案数
枚举元素、原位置、新位置、共n次。
合并的复杂度为
每次合并之后重新预处理一下这个二维前缀和。
处理前缀和的复杂度为
所以我该怎么努力一下降到
是我的做法太朴素了先天不足吗==欢迎大家提供
树形dp
#include <set>#include <ctime>#include <queue>#include <cstdio>#include <bitset>#include <cctype>#include <bitset>#include <cstdlib>#include <cassert>#include <cstring>#include <iostream>#include <algorithm>#define inf (1<<30)#define INF (1ll<<62)#define fi first#define se second#define rep(x,s,t) for(register int x=s,t_=t;x<t_;++x)#define per(x,s,t) for(register int x=t-1,s_=s;x>=s_;--x)#define travel(x) for(int I=last[x],to;~I&&(to=e[I].to);I=e[I].nxt)#define prt(x) cout<<#x<<":"<<x<<" "#define prtn(x) cout<<#x<<":"<<x<<endl#define pb(x) push_back(x)#define hash asfmaljkg#define rank asfjhgskjf#define y1 asggnja#define y2 slfvmusing namespace std;typedef long long ll;typedef pair<int,int> ii;template<class T>void sc(T &x){ int f=1;char c;x=0; while(c=getchar(),c<48)if(c=='-')f=-1; do x=x*10+(c^48); while(c=getchar(),c>47); x*=f;}template<class T>void nt(T x){ if(!x)return; nt(x/10); putchar(x%10+'0');}template<class T>void pt(T x){ if(x<0)putchar('-'),x=-x; if(!x)putchar('0'); else nt(x);}template<class T>void ptn(T x){ pt(x);putchar('\n');}template<class T>void pts(T x){ pt(x);putchar(' ');}template<class T>inline void Max(T &x,T y){if(x<y)x=y;}template<class T>inline void Min(T &x,T y){if(x>y)x=y;}const int maxn=55;const int mod=1e9+7;int n,rt;int last[maxn],ecnt;struct Edge{ int to,nxt;}e[maxn<<1];void ins(int u,int v){ e[ecnt]=(Edge){v,last[u]}; last[u]=ecnt++;}ll cnk[maxn][maxn];ll ans[maxn],ss[maxn];int sz[maxn];int a[maxn],lx[maxn],rx[maxn],dfs_clock;//用来枚举子树元素 void dfs(int x,int f){ lx[x]=++dfs_clock;a[dfs_clock]=x; travel(x)if(to!=f) dfs(to,x); rx[x]=dfs_clock; sz[x]=rx[x]-lx[x]+1;}ll sum[maxn][maxn];ll dp[maxn][maxn][maxn];void deal(int x,int f){ ans[x]=0; travel(x)if(to!=f) deal(to,x); int p=0;ss[x]=1; travel(x)if(to!=f){ ans[x]=(ans[x]*cnk[p+sz[to]][sz[to]]%mod*ss[to]%mod +ans[to]*cnk[p+sz[to]][sz[to]]%mod*ss[x]%mod)%mod;// ans[x]%=mod; rep(i,lx[to],rx[to]+1){//枚举元素 rep(j,0,p+1){//枚举插入的位置 rep(k,1,sz[to]+1){ ll a=cnk[k-1+j][j]*cnk[sz[to]-k+p-j][p-j]%mod; ll b=(mod+sum[n][j]-sum[::a[i]][j])%mod; ll c=(mod+sum[::a[i]][p]-sum[::a[i]][j])%mod; ans[x]+=dp[to][::a[i]][k]*a%mod*(b+c)%mod;/// ans[x]%=mod; } } } rep(i,1,n+1)rep(j,1,n+1)sum[i][j]=0; int np=p+sz[to]; rep(k,1,np+1){//枚举在新排列中的位置 rep(i,lx[x]+1,lx[x]+p+1){//枚举主排列的元素 rep(j,max(k-sz[to],1),min(k,p)+1){//枚举在主排列中的位置 sum[a[i]][k]+=dp[x][a[i]][j]*cnk[k-1][j-1]%mod*cnk[np-k][p-j]%mod*ss[to]%mod;//ss sum[a[i]][k]%=mod; } } rep(i,lx[to],rx[to]+1){//枚举副排列的元素 rep(j,max(k-p,1),min(k,sz[to])+1){//枚举在副排列中的位置 sum[a[i]][k]+=dp[to][a[i]][j]*cnk[k-1][j-1]%mod*cnk[np-k][sz[to]-j]%mod*ss[x]%mod; sum[a[i]][k]%=mod; } } } ss[x]=ss[x]*cnk[np][p]%mod*ss[to]%mod; p=np; rep(i,1,n+1)rep(j,1,n+1){ dp[x][i][j]=sum[i][j]; sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+dp[x][i][j]; } } dp[x][x][sz[x]]=ss[x]; ans[x]+=sum[n][p]-sum[x][p]; ans[x]%=mod;}void solve(){ memset(last,-1,sizeof last); memset(dp,0,sizeof dp); memset(sum,0,sizeof sum); ecnt=0; rep(i,1,n){ int u,v; sc(u);sc(v); ins(u,v);ins(v,u); } dfs_clock=0;dfs(rt,0); deal(rt,0); ptn(ans[rt]);}int main(){// freopen("pro.in","r",stdin);// freopen("chk.out","w",stdout);// int cas;sc(cas); rep(i,0,maxn){ rep(j,1,i) cnk[i][j]=(cnk[i-1][j-1]+cnk[i-1][j])%mod; cnk[i][0]=cnk[i][i]=1; } while(~scanf("%d%d",&n,&rt))solve(); return 0;}
蒟蒻:
开始ans[]合并的不好,从开始写到AC中间隔了几道题,改掉原来错误的合并花了不少时间,封装起来应该会更好看一些,以后写题最好一次写一题(但昨天中途写的那题确实蛮有趣的==)
依然有笔误:ss写成了sz,x和to写混了
变量名应该写的好看一些是吧==以后表示方案数的变量就叫…cas[]?
由诈尸灵魂OIer Tony整理的变量名:
mx to sum tmp num tar now cur top col flag data memo step rank host block delta factor rx ry res cnt pos val str vec tot dir mark tree perm from list spot Q/que mn/mi dp fa ans len dis nxt par cas org sub used left root comb heap edge prime matrix perm
欢迎提供新的变量名:)
- HDU 5789 Permutation
- 【HDU】5789 Permutation【dp】
- hdu 4345 Permutation
- Hdu 4345 Permutation
- HDU 2583 permutation
- hdu 2404 Permutation Recovery
- HDU 4917 Permutation
- hdu-2583 permutation
- HDU 3664 Permutation Counting
- HDU 4345 Permutation dp
- HDU 2583 permutation
- HDU 3667 Permutation Counting
- hdu 5753 Permutation Bo
- HDU 5753 Permutation Bo
- HDU-5753-Permutation Bo
- HDU 5753 Permutation Bo
- 【HDU】5753 Permutation Bo
- Limited Permutation HDU
- Jmeter实现关联
- 医学图像增强之UNSHARP技术(蒙片)
- BOOT.IMG文件结构
- 【985系列】985的最大和难题
- viewpager 滑动崩溃
- HDU 5789 Permutation
- hduoj 2546 饭卡(背包)
- [lintcode] Binary Tree Maximum Path Sum II
- POJ 2409 Let it Bead (Polya) .
- 随手整理
- css left/right拉伸和width同时存在
- ios-正则表达式
- hdu4725——The Shortest Path in Nya Graph(SPFA+两层图)
- POJ 1655 (树dp or 树重心)