TopCoder 14084 BearPermutations2【笛卡爾樹+dp】
阿新 • • 發佈:2019-05-03
d+ -- code sum turn topcoder long long memset opcode
傳送:https://vjudge.net/problem/TopCoder-14084
只是利用了笛卡爾樹的性質,設f[i][j]為區間[i,j]的貢獻,然後枚舉中間最大的點k來轉移,首先是兩側小區間貢獻的,f[i][k-1]*fac[j-k]+f[k+1][j]*fac[k-i],大概是方案數相乘的形式
然後考慮中間點的兒子的貢獻,是\( fac[k-i-1]|*fac[j-k-1]|*sum_{l=i}^{k-1}\sum_{r=k+1}^{j}r-l \),前面表示兩側任意排列,後面兩個求和可以化簡
然後最後整體乘c[j-i][k-i]表示選出一部分作為左兒子
#include<iostream> #include<cstdio> #include<cstring> using namespace std; class BearPermutations2 { private: long long mod,f[105][105],c[105][105],fac[105]; public: long long clc(long long l,long long r) { return (l+r)*(r-l+1)/2%mod; } int getSum(int n,int MOD) { memset(f,0,sizeof(f)); memset(c,0,sizeof(c)); mod=MOD; fac[0]=1; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod; c[0][0]=1; 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]+c[i-1][j-1])%mod; } for(int i=n;i>=1;i--) for(int j=i;j<=n;j++) for(int k=i;k<=j;k++) { if(k!=i) f[i][j]=(f[i][j]+c[j-i][k-i]*f[i][k-1]%mod*fac[j-k]%mod)%mod; if(k!=j) f[i][j]=(f[i][j]+c[j-i][k-i]*f[k+1][j]%mod*fac[k-i]%mod)%mod; if(k!=i&&k!=j) f[i][j]=(f[i][j]+c[j-i][k-i]*fac[k-i-1]%mod*fac[j-k-1]%mod*(clc(k+1,j)*(k-i)%mod-clc(i,k-1)*(j-k)%mod+mod)%mod)%mod; } return (f[1][n]+mod)%mod; } };
TopCoder 14084 BearPermutations2【笛卡爾樹+dp】