P4609题解
zzz13579zzz · · 题解
P4609 [FJOI2016] 建筑师
外训听完组合数学后题单里的,但觉得
首先,由于要求前后缀最大值的个数,所以我们考虑将数字从大到小插入
记
考虑将下一个数,即当前最大值插入对答案的影响。若放在两边,答案不变,前后缀最大值长度增加。若插在中间,由于已插入的数都比当前数大,不会对前后缀最大值产生影响,所以可以随便插,答案乘上
初值为
复杂度
但当你兴冲冲写完一交,满屏的
所以我们先将询问离线,按照
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,M=1e9+7;
int n,A,B,dp[2][110][110],ans[N];
struct que{
int n,a,b,id;
}q[N];
bool cmp(que x,que y){return x.n<y.n;}
signed main(){
int T;
cin>>T;
for(int i=1;i<=T;i++){
cin>>q[i].n>>q[i].a>>q[i].b;
q[i].id=i;
}
sort(q+1,q+T+1,cmp);
int l=1;
while(q[l].n==1 and l<=T){ans[q[l].id]=((q[l].a==1)and(q[l].b==1));l++;}
dp[0][1][2]=dp[0][2][1]=1;
while(q[l].n==2 and l<=T){ans[q[l].id]=dp[0][q[l].a][q[l].b];l++;}
for(int i=3;i<=q[T].n;i++){
for(int j=1;j<=min(i,100);j++){
for(int k=1;k<=min(i,100);k++){
dp[i&1][j][k]=(dp[i&1^1][j-1][k]+dp[i&1^1][j][k-1]+1ll*dp[i&1^1][j][k]*(i-2))%M;
}
}
while(q[l].n==i and l<=T){ans[q[l].id]=dp[i&1][q[l].a][q[l].b];l++;}
}
for(int i=1;i<=T;i++)cout<<ans[i]<<'\n';
return 0;
}
注意