bzoj 4621 Tc605 Posted on 2019-05-29 | Views: $dp$ . 一个数字只可以往左右拓展,把周围的数变成和它一样的数.所以最终状态一定是一些数字段拼起来的,而且数字之间相对的前后顺序不会改变. 对最终状态进行 $dp$ .设 $f(i,j)$ 表示考虑了前 $i$ 个位置,操作了 $j$ 次的情况总数.一个数字段最多操作一次,处理出每个数字左右延伸的范围,枚举拓展的右端点进行转移即可. 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int P=1e9+7;inline int add(int a,int b){ return (a + b) % P;}inline int mul(int a,int b){ return 1LL * a * b % P;}const int MAXN=512;int n,m,a[MAXN],f[MAXN][MAXN];int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) a[i]=read(); f[0][0]=1; for(int i=1;i<=n;++i) { int l=i; while(l>1 && a[l-1]<a[i]) --l; int r=i; while(r<n && a[r+1]<a[i]) ++r; f[i][m]=add(f[i][m],f[i-1][m]); for(int j=m;j>=1;--j) { int tmp=f[l-1][j-1]; for(int k=l;k<=r;++k) { f[k][j]=add(f[k][j],tmp); tmp=add(tmp,f[k][j-1]); } f[i][j-1]=add(f[i][j-1],f[i-1][j-1]); f[i][j]=add(f[i][j],-f[i-1][j-1]); } } int ans=0; for(int i=0;i<=m;++i) ans=add(ans,f[n][i]); cout<<add(ans,P)<<endl; return 0;}