题意就是求每个数在所有方案中的最终值的和。显然一个数经过若干次变化一定会变成另外一个数,那么离散化后,令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个数,这样再转移就会出错。
那么(根据jry老司机的博客)令f[k][x][y]表示经过k轮后,恰好[x,y]这个范围内的数都<=从小到大第j数的方案数,这样就可以转移了。显然f[k][x][y]必然由f[k][u(u<x)][y]和f[k][x][v(v>y)],然后操作任意[t(t<l),u]和[v,t(t>r)]得到;或者直接由f[k][x][y],然后任意一个操作[u,v],其中[u,v]∩[x,y]=0得到。
然后重新领g[i][j]表示第i个数最终<=从小到大第j个数的方案数,然后减一减即可。
后来有一个卡常的技巧是每一轮都用long long暴力加起来,这一轮结束的时候再取模。这样瞬间应该可以快很多。
AC代码如下:
#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;
}
by lych
2016.5.3