[hackerrank random]

Description

给出一个数列{d},|d|=n。
依次进行a次操作1和b次操作2。
操作1:随机一个二元组(l,r)[l< r],交换d[l],d[r]
操作2:随机一个二元组(l,r)[l< r],翻转区间[l,r]
最后随机一个二元组(l,r)[l< r],求出区间[l,r]的和。
求最终答案的期望值。
n<=1000,a<=10^9,b<=10

Solution

被WorldWide_D强推了这道题~花了三节数学课搞了出来=w=
先考虑最简单的。
如果我们求出了e(i)表示i这个位置的期望值,那么它对答案的贡献就是覆盖它的区间个数,注意l不能等于r

Ans=i=1ne(i)i(ni+1)1n(n1)/2

然后设E(i)表示i在进行完1操作之后i位置的期望值,那么e(i)可以用一个简单的dp转移过来。
设Fi,j表示i在进行了j次2操作之后的期望值。
枚举上一次的一个k对i进行贡献,发现区间个数是可以算的。
所有其他区间贡献完之后剩下的就是Fi,j-1转移到Fi,j的区间个数。
转移就不写了~
然后考虑第一步中,j对i的贡献。
可以写一个dp,转移显然。
F[0,j]=1,F[i,l]=k!=iF[k,l1]/(n(n1)/2)+F[i,j1](n2)/n
发现每一层F只会有两种不同的取值,设为A和B。
那么
Ai=Ai1[n2n+n2n(n1)/2]+Bi11n(n1)/2
Bi=Ai1n1n(n1)/2+Bi1n2n
写个矩阵乘法就好了~
如果j不等于i那么用A转移,否则用B转移。
然后这道题就解决了。。。
结果这样子做精度不够高,本机对拍被卡掉了,然而上去交过掉了233
另一个解法

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef double db;
const int N=1e3+5;
int n,a,b,d[N];
db f[N][11],ans;
struct matrix{
    db a[2][2];
    friend matrix operator * (matrix y, matrix z) {
        matrix x;memset(x.a,0,sizeof(x.a));
        fo(i,0,1) fo(j,0,1) fo(k,0,1) x.a[i][j]+=y.a[i][k]*z.a[k][j];
        return x;
    }
}g,t;
int main() {
    scanf("%d%d%d",&n,&a,&b);
    fo(i,1,n) scanf("%d",&d[i]);
    db nn=n*(n-1)/2;
    g.a[0][0]=((n-2)*1.0/n+(n-2)*1.0/nn);
    g.a[0][1]=(n-1)*1.0/nn;
    g.a[1][0]=1.0/nn;
    g.a[1][1]=(n-2)*1.0/n;
    memcpy(t.a,g.a,sizeof(t.a));
    for(a--;a;a/=2,g=g*g) if (a&1) t=t*g;
    fo(i,1,n) {
        fo(j,1,n) if (i!=j) f[i][0]+=d[j]*t.a[1][0];
        f[i][0]+=d[i]*t.a[1][1];
    }
    fo(k,1,b) fo(i,1,n) {
        f[i][k]=f[i][k-1];
        fo(j,1,i-1) f[i][k]+=(f[j][k-1]-f[i][k-1])*min(j,n-i+1)*1.0/nn;
        fo(j,i+1,n) f[i][k]+=(f[j][k-1]-f[i][k-1])*min(i,n-j+1)*1.0/nn; 
    }
    fo(i,1,n) ans+=f[i][b]*(i*(n-i+1)-1)*1.0/nn;
    printf("%.6lf\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值