不連續的處理很麻煩c++
致使序列DP又找不到優秀的子問題git
自底向上考慮?ui
創建小根堆笛卡爾樹spa
每一個點的意義是:高度是(本身-father)的橫着的極大矩形.net
子問題具備遞歸的優秀性質code
f[i][j]i爲根子樹,放j個blog
兒子揹包合併遞歸
考慮本層的矩形放多少個get
枚舉一共放t個,本層放j個it
對於子樹裏的放置的t-j個,不論怎麼放,必定佔據了t-j列,剩下W[i]-(t-j)個位置
轉移是:
https://blog.csdn.net/qq_39972971/article/details/79359547
當前節點的:枚舉放多少個、佔哪些行、佔哪些列、具體前後順序。
代碼:
C(n,m)時刻注意n>=0&&m>=0&&n>=m不然<0越界還看不出來調死
#include<bits/stdc++.h> #define reg register int #define il inline #define int long long #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=505; const int mod=1e9+7; ll f[N][N]; ll tmp[N]; ll jie[1000000+5],inv[1000000+5]; int qm(int x,int y){ int ret=1; while(y){ if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int n,k; int ch[N][2],sz[N],fa[N],h[N]; int sta[N],top; int a[N]; int build(){ top=0; int las=0; for(reg i=1;i<=n;++i){ las=0; while(top&&a[i]<a[sta[top]]){ las=sta[top]; --top; if(top&&a[sta[top]]>a[i]) ch[sta[top]][1]=las,fa[las]=sta[top]; else ch[i][0]=las,fa[las]=i; } sta[++top]=i; } while(top>1) ch[sta[top-1]][1]=sta[top],fa[sta[top]]=sta[top-1],--top; return sta[1]; } int C(int n,int m){ if(n<0||m<0||n<m) return 0; return (ll)jie[n]*inv[m]%mod*inv[n-m]%mod; } void dfs(int x){ // cout<<" x ff "<<x<<" "<<ff<<endl; f[x][0]=1; if(!x) return; sz[x]=1; dfs(ch[x][0]);dfs(ch[x][1]); sz[x]+=sz[ch[x][0]]+sz[ch[x][1]]; h[x]=a[x]-a[fa[x]]; f[x][0]=1; for(reg s=0;s<=1;++s){ if(!ch[x][s]) continue; int y=ch[x][s]; for(reg j=k;j>=0;--j){ for(reg t=1;t<=j;++t){ f[x][j]=(f[x][j]+f[x][j-t]*f[y][t])%mod; } } } for(reg i=k;i>=0;--i){ for(reg j=1;j<=min(min(i,sz[x]),h[x]);++j){ f[x][i]=(f[x][i]+f[x][i-j]*C(h[x],j)%mod*C(sz[x]-(i-j),j)%mod*jie[j]%mod)%mod; } } } int main(){ rd(n);rd(k); int m=0; for(reg i=1;i<=n;++i) rd(a[i]),m=max(m,a[i]); m=max(m,max(n,k)); jie[0]=1; for(reg i=1;i<=m;++i) jie[i]=(ll)jie[i-1]*i%mod; inv[m]=qm(jie[m],mod-2); for(reg i=m-1;i>=0;--i) inv[i]=(ll)inv[i+1]*(i+1)%mod; int rt=build(); // cout<<" rt "<<rt<<endl; f[0][0]=1; dfs(rt); printf("%lld",f[rt][k]); return 0; } } signed main(){ // freopen("data.in","r",stdin); // freopen("my.out","w",stdout); Miracle::main(); return 0; }
總結:
建出笛卡爾樹後有優秀的子問題性質
當前矩形的填法能夠歸爲:先找到幾行幾列變成子正方形,L行L列的正方形的填法就是L!