传送门:bzoj4574
转自lych_cys
题意就是求每个数在所有方案中的最终值的和。显然一个数经过若干次变化一定会变成另外一个数,那么离散化后,令g[i][j]表示i这个数最终变成从小到大第j个的方案数。一个直观的思路是,我们枚举j,那么显然g[i][j]>0的i的范围是(l,r),其中a[l]和a[r]是第j大的数两侧分别第一个大于这个从小到大第j个数的数(由于是随机因此可以假定没有两个数相同)。此时,
如果令f[k][x][y]表示经过k轮后,恰好是[x,y]这个范围内的数都变成了从小到大第j个数的方案数。但是这样会存在问题,就是如果某一轮的操作跨过了l或r,就会造成[l,r]中某一些数>从小到大第j个数,这样再转移就会出错。
那么令f[k][x][y]表示经过k轮后,恰好[x,y]这个范围内的数都<=从小到大第j数的方案数,这样就可以转移了。显然f[k][x][y]必然由f[k][u(u
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 #define ll long long #define N 405 #define calc(x) ((x)*((x)+1)>>1) using namespace std; int n,m,f[2][N][N],g[N][N],s[N][N],a[N],b[N],c[N],rnk[N]; bool cmp(const int &x,const int &y){ return a[x]<a[y]; } int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } void solve(int l,int r,int p){ int i,j,k,last,now=0,tmp; for (i=l; i<=r; i++) for (j=i; j<=r; j++) f[0][i][j]=0; f[0][l][r]=1; for (k=1; k<=m; k++){ last=now; now^=1; for (i=l; i<=r; i++){ tmp=0; for (j=r; j>=i; j--){ f[now][i][j]=tmp; tmp=(tmp+(ll)f[last][i][j]*(n-j))%mod; } } for (i=l; i<=r; i++) c[i]=0; for (i=l; i<=r; i++) for (j=i; j<=r; j++){ f[now][i][j]=(f[now][i][j]+c[j])%mod; c[j]=(c[j]+(ll)f[last][i][j]*(i-1))%mod; } for (i=l; i<=r; i++) for (j=i; j<=r; j++) f[now][i][j]=(f[now][i][j]+(ll)f[last][i][j]*s[i][j])%mod; } for (i=l; i<=r; i++){ tmp=0; for (j=r; j>=i; j--){ tmp=(tmp+f[now][i][j])%mod; g[j][rnk[p]]=(g[j][rnk[p]]+tmp)%mod; } } } int main(){ n=read(); m=read(); int i,j,l,r,tmp,ans; for (i=1; i<=n; i++){ a[i]=read(); b[i]=i; } sort(b+1,b+n+1,cmp); for (i=1; i<=n; i++) rnk[b[i]]=i; for (i=1; i<=n; i++) for (j=i; j<=n; j++) s[i][j]=calc(i-1)+calc(n-j)+calc(j-i+1); for (i=1; i<=n; i++){ l=r=i; while (l>1 && a[l-1]<a[i]) l--; while (r<n && a[r+1]<a[i]) r++; solve(l,r,i); } for (i=1; i<=n; i++){ tmp=ans=0; for (j=1; j<=n; j++) if (g[i][j]){ g[i][j]-=tmp; if (g[i][j]<0) g[i][j]+=mod; ans=(ans+(ll)g[i][j]*a[b[j]])%mod; tmp=(tmp+g[i][j])%mod; } printf("%d%c",ans,(i<n)?' ':'\n'); } return 0; }