codeforces 513G3 Inversions problem

190 篇文章 2 订阅
84 篇文章 2 订阅

题面

题意

给出n(<=100)个数,每次操作随机选择一个区间翻转,求k(<=1e9)次操作后逆序对的期望数量。

做法

虽然操作次数范围为1e9,但是我们可以发现到了后面的操作,对答案的影响将越来越小,因此当操作数量特别大时,我们可以以前900(经过不断尝试得出的数字)次操作之后的答案为最终答案。
接下来就是概率dp,考虑每两个数组成逆序对后对答案的贡献,dp[i][j]表示此时i在j前的期望,转移的时候考虑以下四种情况:
1.翻转的区间不覆盖i,j:考虑左右端点同时在:[1,i-1],[i+1,j-1],[j+1,n]三种情况。
2.翻转的区间同时覆盖i,j:考虑左端点在[1,i],右端点在[j,n]的情况.
3.翻转的区间仅覆盖i:考虑左右端点分别在i的两端且右端点在j的左边时的情况
4.翻转的区间仅覆盖j:考虑左右端点分别在j的两端且左端点在i的右边时的情况
因为时间复杂度为O(n^3*min(k,900)),所以常数比较重要,我加了O(3)等优化后才过去。

代码

#pragma GCC diagnostic error "-std=c++11"
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<iostream>
#include<cstdio>
#define db double
#define N 110
#define CS 900
using namespace std;

int n,m,num[N];
db dp[N][N],tmp[N][N],ans,sum;

inline db calc(int u){return (db)(u)*(db)(u+1)/2;}

int main()
{
    int i,j,k,t,ii;
    cin>>n>>m;sum=n*(n+1)/2;
    for(i=1;i<=n;i++) scanf("%d",&num[i]);
    m=min(m,CS);
    for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) dp[i][j]=1;
    for(t=1;t<=m;t++)
    {
        for(i=1;i<=n;i++) for(j=1;j<=n;j++) tmp[i][j]=0;
        for(i=1;i<=n;i++)
        {
            for(j=i+1;j<=n;j++)
            {
                tmp[i][j]=dp[i][j]*(calc(i-1)+calc(j-i-1)+calc(n-j))/sum;
                //i,j
                for(k=1-i;k+j<=n;k++)
                    tmp[i][j]+=(1-dp[i+k][j+k])*min(min(i,i+k),n-max(j,j+k)+1)/sum;
                //i
                for(k=1-i;k<j-i;k++)
                    tmp[i][j]+=dp[i+k][j]*min(min(i,i+k),j-max(i,i+k))/sum;
                //j
                for(k=i-j+1;k+j<=n;k++)
                    tmp[i][j]+=dp[i][j+k]*min(min(j,j+k)-i,n-max(j,j+k)+1)/sum;
            }
        }
        memcpy(dp,tmp,sizeof(tmp));
    }
    for(i=1;i<=n;i++)
    {
        for(j=i+1;j<=n;j++)
        {
            if(num[i]>num[j]) ans+=dp[i][j];
            else ans+=1-dp[i][j];
        }
    }
    printf("%.10f",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值