bzoj 5346: tree (其实是是某次雅礼集训的题)
用prufer序列的公式直接dp,O(n^4)的算法简简单单就写出来了23333.
按理说 O(n^4)是需要优化成O(n^3)才能过的,然鹅我也不知道我怎么过了23333
(那就懒得优化了hhhhh)
(后来翻了翻std,发现标算就是O(n^4)的。。。。迷)
/* f[i][j] -> 已经选了i个节点,度数和为j 的∑( π1/(degree[i]-1)!) */ #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define ll long long using namespace std; const int maxn=105,ha=1004535809; int f[maxn][maxn*2],n,d[maxn],jc[maxn],ni[maxn],M; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;} inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;} inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void init(){ jc[0]=1; for(int i=1;i<=100;i++) jc[i]=jc[i-1]*(ll)i%ha; ni[100]=ksm(jc[100],ha-2); for(int i=100;i;i--) ni[i-1]=ni[i]*(ll)i%ha; } inline void solve(){ f[0][0]=1; for(int i=1;i<=n;i++) for(int j=i-1;j>=0;j--) for(int k=M;k>=0;k--) if(f[j][k]) for(int u=min(d[i],M-k);u;u--) ADD(f[j+1][k+u],f[j][k]*(ll)ni[u-1]%ha); } inline void calc(){ printf("%d ",n); for(int i=2;i<=n;i++) printf("%d ",f[i][(i-1)<<1]*(ll)jc[i-2]%ha); puts(""); } int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); init(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",d+i),d[i]=min(d[i],n-1); M=n*2-2,solve(),calc(); return 0; }
我爱学习,学习使我快乐