正睿2019省選十連測day3T3(笛卡爾樹,dp)
阿新 • • 發佈:2018-12-22
題面描述
有一個11到nn的排列p1,p2,p3,…,pn,你會對它進行若干輪操作,每一輪操作,你會保留序列中極大的數,也就是說對於每個數字,如果它比相鄰的數字都大,那麼會被保留下來。比如一個排列(3,2,5,1,4,6),經過一輪操作之後序列變成(3,5,6),第二輪操作之後序列變成(6),經過恰好2輪之後序列裡只有一個元素。
請問有多少個長度為n的序列,經過恰好k次操作之後,序列裡只有一個元素,由於答案很大,對一個素數P取模。輸入格式
第一行三個正整數n,k,P,其中P表示模數,保證P是素數,且108≤P≤109。
輸出格式
輸出一個數,表示答案。
樣例輸入
5 3 100000007
樣例輸出
4
資料規模
對於 10% 的資料,n≤10。
對於 30% 的資料,n≤20。
對於 60% 的資料,n≤100。
對於 100%1 的資料, 1≤k≤n≤103。
同時和位置和數字權值有關的問題。考慮轉化到笛卡爾樹上
以位置為二叉搜尋樹的鍵值,數字為堆的鍵值建立笛卡爾樹
可以發現不考慮邊界,記
為一個點被消去的時間
可以得到
邊界需要特殊處理
把這個過程換成計數
表示
個點,
輪消去的方案
表示
個點,
輪消去,且當前根在邊界上的方案
直接轉移即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
int num = 0;char c = getchar();bool flag = true;
while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
if(flag) return num;else return -num;
}
int n,m,p;
int f[1010][13],g[1010][13];
int c[1010][1010];
inline void chmax(int &a,int b){if(a<b)a=b;}
inline int max(int a,int b){return a>b?a:b;}
inline int mul(int a,int b){return 1ll*a*b%p;}
inline int calc(int a,int b){return (a+=b)>=p?a-=p:a;}
int main()
{
n = rd();m = rd();p = rd();
f[0][0] = g[0][0] = 1;
c[0][0] = 1;
rep(i,1,n){c[i][0] = c[i][i] = 1;rep(j,1,i-1) c[i][j] = calc(c[i-1][j-1],c[i-1][j]);}
rep(i,1,n)
rep(j,0,i-1)
{//f[j][].f[k][]->f[i][]
int k = i-j-1;
int t = c[i-1][j];
rep(x,0,m) if(f[j][x]||g[j][x])
rep(y,0,m) if(f[k][y])
f[i][x==y?x+1:max(x,y)] = calc(f[i][x==y?x+1:max(x,y)],mul(f[j][x],mul(f[k][y],t))),
g[i][max(x,y+1)] = calc(g[i][max(x,y+1)],mul( g[j][x] , mul(f[k][y] , t) ));
}
int ans = 0;
rep(i,0,n-1)
{
int j = n-i-1;
rep(x,0,m) rep(y,0,m) if(x == m || y == m)
ans = calc(ans,mul( g[i][x] , mul(g[j][y],c[n-1][i]) ));
}
printf("%d\n",ans);
return 0;
}