【UOJ#196】【BZOJ4574】[Zjoi2016]线段树
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4574
考虑数字随机并且值域够大,我们将元素离散化并且不需要去重。
令$g[i]$表示每一个位置的期望大小。
那么${Ans=\sum (g[i]*(\frac{n(n+1))}{2})^{q})}$
考虑根据这个${(\frac{n(n+1))}{2})^{q}}$转换一下问题,是不是可以变成:
---------------------------------------------分割线----------------------------------------------------------------
令${sum[i][j]}$表示序列的第$i$个位置的元素在$q$次操作后变成了离散化之后$j$大的方案数。
那么${Ans=\sum_{i=1}^{n}\sum _{j=1}^{n}(sum[i][j]*X[j])}$ //$X[i]$表示第离散化之后的第$i$个元素原本对应的数字的大小。
---------------------------------------------分割线----------------------------------------------------------------
考虑如何求${sum}$数组。
从左至右枚举离散化数列每一位上的值(设我枚举的数字为第${E}$大),我们知道一个数至多能够影响到一个有限的区间,即区间${[L,R]}$中每一个数字都没有它大。
令${DP[k][i][j]}$表示第$k$次操作之后区间${[i,j]}$的值都小于等于当前枚举值的方案数。
转移:
${DP[k][i][j]=\sum _{u=L}^{i-1}(DP[k-1][u][j]*(u-1))+\sum _{v=j+1}^{R}(DP[k-1][i][v]*(n-v))+DP[k-1][i][j]*(cnt[i-1]+cnt[j-i+1]+cnt[n-j])}$
那么为啥是这样呢?
我来尝试解释一下第一项即${\sum _{u=L}^{i-1}(DP[k-1][u][j]*(u-1))}$
这个转移其实是从区间${[U,j]}$转移到区间${[i,j]}$,拿为啥要乘上一个系数$(u-1)$,是因为我要使得${[u,i-1]}$这段区间内不再小于等于当前枚举的值。所以只要选取了${[1,u-1]}$这段区间内的一个元素作为操作的左端点,固定右端点为${i-1}$则一定会存在一个数字(因为第${L-1}$个数一定大于当前枚举的数)使得${[u,i-1]}$这个区间的数不再小于等于当前枚举的数。
第二项的理解和第一项基本相同。
第三项就比较简单了,如果我选取的区间不跨过第$i$个位置或第$j$个位置,那就不会产生状态的改变,可与之间从区间${[i,j]}$向区间${[i,j]}$转移
对于每一个枚举的数字就算出了$DP$数组,我为了方便统计答案再设一个数组${sum{}'}$表示序列的第$i$个位置的元素在$q$次操作后变成了离散化之后数小于等于$j$大数的方案数。
${sum{}'[i][E]=sum{}'[i][E]+\sum _{u=L}^{R-1}\sum _{v=u+1}^{R}DP[q][u][v]}$
最后在利用${sum{}'}$数组计算出${sum}$数组。
${Ans=\sum_{i=1}^{n}\sum _{j=1}^{n}(sum[i][j]*X[j])}$
参考:http://blog.csdn.net/qq_34637390/article/details/51290087
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 410 10 #define llg long long 11 #define md (llg)((1e9)+7) 12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 13 #define DD(i,j,k) dp[(i)%2][j][k]//方便滚动数组优化空间 14 llg n,m,q,x[maxn],rank[maxn],L,R,wz[maxn]; 15 llg cnt[maxn],dp[2][maxn][maxn],sum[maxn][maxn],A[maxn][maxn]; 16 17 inline bool cmp(llg a,llg b) {return x[a]<x[b];} 18 19 void init() 20 { 21 cin>>n>>q; 22 for (llg i=1;i<=n;i++) scanf("%lld",&x[i]); 23 for (llg i=1;i<=n;i++) wz[i]=i; 24 sort(wz+1,wz+n+1,cmp); 25 for (llg i=1;i<=n;i++) rank[wz[i]]=i;//第i个元素是第rank[i]小的 26 //离散化 27 for (llg i=1;i<=n;i++) cnt[i]=(i*i+i)/2; 28 for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)A[i][j]=cnt[i-1]+cnt[n-j]+cnt[j-i+1]; 29 } 30 31 void DP(llg now) 32 { 33 for (llg i=L;i<=R;i++) for (llg j=L;j<=R;j++) DD(0,i,j)=DD(1,i,j)=0; 34 DD(0,L,R)=1; 35 llg val; 36 for (llg k=1;k<=q;k++) 37 { 38 for (llg i=L;i<=R;i++) 39 { 40 val=0; 41 for(int j=R;j>=i;j--) 42 { 43 DD(k,i,j)=val; val=(val+DD(k-1,i,j)*(n-j))%md;//计算第二项 44 } 45 } 46 for (llg j=L;j<=R;j++) 47 { 48 val=0; 49 for(llg i=L;i<=j;i++) 50 { 51 DD(k,i,j)=(DD(k,i,j)+val)%md; val=(val+DD(k-1,i,j)*(i-1));//计算第一项 52 } 53 } 54 for (llg i=L;i<=R;i++) 55 { 56 for (llg j=i;j<=R;j++) 57 { 58 DD(k,i,j)=(DD(k,i,j)+(DD(k-1,i,j)*A[i][j]))%md;//计算第三项 59 } 60 } 61 } 62 for (llg i=L;i<=R;i++) 63 { 64 val=0; 65 for (llg j=R;j>=i;j--) 66 { 67 val+=DD(q,i,j); val%=md; 68 sum[j][rank[now]]+=val; 69 sum[j][rank[now]]%=md; 70 } 71 } 72 } 73 74 int main() 75 { 76 //yyj("seg"); 77 init(); 78 for (llg i=1;i<=n;i++) 79 { 80 L=R=i; 81 while (L && x[L]<=x[i]) L--; L++; 82 while (R<=n && x[R]<=x[i]) R++; R--; 83 //预处理第i个元素可以影响的区间 84 DP(i); 85 } 86 87 llg ans=0; 88 for (llg i=1;i<=n;i++) 89 { 90 ans=0; 91 for (llg j=1;j<=n;j++) 92 { 93 if (sum[i][j]==0) continue; 94 for (llg k=1;k<j;k++) sum[i][j]-=sum[i][k]; 95 while (sum[i][j]<0) sum[i][j]+=md; 96 ans+=x[wz[j]]*sum[i][j]; ans%=md; 97 } 98 while (ans<0) ans+=md; 99 printf("%lld",ans); 100 if (i!=0) printf(" "); 101 } 102 return 0; 103 }